// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package textproto

import (
	
	
	
	
	
	
	
)

// A Reader implements convenience methods for reading requests
// or responses from a text protocol network connection.
type Reader struct {
	R   *bufio.Reader
	dot *dotReader
	buf []byte // a re-usable buffer for readContinuedLineSlice
}

// NewReader returns a new Reader reading from r.
//
// To avoid denial of service attacks, the provided bufio.Reader
// should be reading from an io.LimitReader or similar Reader to bound
// the size of responses.
func ( *bufio.Reader) *Reader {
	commonHeaderOnce.Do(initCommonHeader)
	return &Reader{R: }
}

// ReadLine reads a single line from r,
// eliding the final \n or \r\n from the returned string.
func ( *Reader) () (string, error) {
	,  := .readLineSlice()
	return string(), 
}

// ReadLineBytes is like ReadLine but returns a []byte instead of a string.
func ( *Reader) () ([]byte, error) {
	,  := .readLineSlice()
	if  != nil {
		 := make([]byte, len())
		copy(, )
		 = 
	}
	return , 
}

func ( *Reader) () ([]byte, error) {
	.closeDot()
	var  []byte
	for {
		, ,  := .R.ReadLine()
		if  != nil {
			return nil, 
		}
		// Avoid the copy if the first call produced a full line.
		if  == nil && ! {
			return , nil
		}
		 = append(, ...)
		if ! {
			break
		}
	}
	return , nil
}

// ReadContinuedLine reads a possibly continued line from r,
// eliding the final trailing ASCII white space.
// Lines after the first are considered continuations if they
// begin with a space or tab character. In the returned data,
// continuation lines are separated from the previous line
// only by a single space: the newline and leading white space
// are removed.
//
// For example, consider this input:
//
//	Line 1
//	  continued...
//	Line 2
//
// The first call to ReadContinuedLine will return "Line 1 continued..."
// and the second will return "Line 2".
//
// Empty lines are never continued.
//
func ( *Reader) () (string, error) {
	,  := .readContinuedLineSlice(noValidation)
	return string(), 
}

// trim returns s with leading and trailing spaces and tabs removed.
// It does not assume Unicode or UTF-8.
func trim( []byte) []byte {
	 := 0
	for  < len() && ([] == ' ' || [] == '\t') {
		++
	}
	 := len()
	for  >  && ([-1] == ' ' || [-1] == '\t') {
		--
	}
	return [:]
}

// ReadContinuedLineBytes is like ReadContinuedLine but
// returns a []byte instead of a string.
func ( *Reader) () ([]byte, error) {
	,  := .readContinuedLineSlice(noValidation)
	if  != nil {
		 := make([]byte, len())
		copy(, )
		 = 
	}
	return , 
}

// readContinuedLineSlice reads continued lines from the reader buffer,
// returning a byte slice with all lines. The validateFirstLine function
// is run on the first read line, and if it returns an error then this
// error is returned from readContinuedLineSlice.
func ( *Reader) ( func([]byte) error) ([]byte, error) {
	if  == nil {
		return nil, fmt.Errorf("missing validateFirstLine func")
	}

	// Read the first line.
	,  := .readLineSlice()
	if  != nil {
		return nil, 
	}
	if len() == 0 { // blank line - no continuation
		return , nil
	}

	if  := ();  != nil {
		return nil, 
	}

	// Optimistically assume that we have started to buffer the next line
	// and it starts with an ASCII letter (the next header key), or a blank
	// line, so we can avoid copying that buffered data around in memory
	// and skipping over non-existent whitespace.
	if .R.Buffered() > 1 {
		,  := .R.Peek(2)
		if len() > 0 && (isASCIILetter([0]) || [0] == '\n') ||
			len() == 2 && [0] == '\r' && [1] == '\n' {
			return trim(), nil
		}
	}

	// ReadByte or the next readLineSlice will flush the read buffer;
	// copy the slice into buf.
	.buf = append(.buf[:0], trim()...)

	// Read continuation lines.
	for .skipSpace() > 0 {
		,  := .readLineSlice()
		if  != nil {
			break
		}
		.buf = append(.buf, ' ')
		.buf = append(.buf, trim()...)
	}
	return .buf, nil
}

// skipSpace skips R over all spaces and returns the number of bytes skipped.
func ( *Reader) () int {
	 := 0
	for {
		,  := .R.ReadByte()
		if  != nil {
			// Bufio will keep err until next read.
			break
		}
		if  != ' ' &&  != '\t' {
			.R.UnreadByte()
			break
		}
		++
	}
	return 
}

func ( *Reader) ( int) ( int,  bool,  string,  error) {
	,  := .ReadLine()
	if  != nil {
		return
	}
	return parseCodeLine(, )
}

func parseCodeLine( string,  int) ( int,  bool,  string,  error) {
	if len() < 4 || [3] != ' ' && [3] != '-' {
		 = ProtocolError("short response: " + )
		return
	}
	 = [3] == '-'
	,  = strconv.Atoi([0:3])
	if  != nil ||  < 100 {
		 = ProtocolError("invalid response code: " + )
		return
	}
	 = [4:]
	if 1 <=  &&  < 10 && /100 !=  ||
		10 <=  &&  < 100 && /10 !=  ||
		100 <=  &&  < 1000 &&  !=  {
		 = &Error{, }
	}
	return
}

// ReadCodeLine reads a response code line of the form
//	code message
// where code is a three-digit status code and the message
// extends to the rest of the line. An example of such a line is:
//	220 plan9.bell-labs.com ESMTP
//
// If the prefix of the status does not match the digits in expectCode,
// ReadCodeLine returns with err set to &Error{code, message}.
// For example, if expectCode is 31, an error will be returned if
// the status is not in the range [310,319].
//
// If the response is multi-line, ReadCodeLine returns an error.
//
// An expectCode <= 0 disables the check of the status code.
//
func ( *Reader) ( int) ( int,  string,  error) {
	, , ,  := .readCodeLine()
	if  == nil &&  {
		 = ProtocolError("unexpected multi-line response: " + )
	}
	return
}

// ReadResponse reads a multi-line response of the form:
//
//	code-message line 1
//	code-message line 2
//	...
//	code message line n
//
// where code is a three-digit status code. The first line starts with the
// code and a hyphen. The response is terminated by a line that starts
// with the same code followed by a space. Each line in message is
// separated by a newline (\n).
//
// See page 36 of RFC 959 (https://www.ietf.org/rfc/rfc959.txt) for
// details of another form of response accepted:
//
//  code-message line 1
//  message line 2
//  ...
//  code message line n
//
// If the prefix of the status does not match the digits in expectCode,
// ReadResponse returns with err set to &Error{code, message}.
// For example, if expectCode is 31, an error will be returned if
// the status is not in the range [310,319].
//
// An expectCode <= 0 disables the check of the status code.
//
func ( *Reader) ( int) ( int,  string,  error) {
	, , ,  := .readCodeLine()
	 := 
	for  {
		,  := .ReadLine()
		if  != nil {
			return 0, "", 
		}

		var  int
		var  string
		, , ,  = parseCodeLine(, 0)
		if  != nil ||  !=  {
			 += "\n" + strings.TrimRight(, "\r\n")
			 = true
			continue
		}
		 += "\n" + 
	}
	if  != nil &&  &&  != "" {
		// replace one line error message with all lines (full message)
		 = &Error{, }
	}
	return
}

// DotReader returns a new Reader that satisfies Reads using the
// decoded text of a dot-encoded block read from r.
// The returned Reader is only valid until the next call
// to a method on r.
//
// Dot encoding is a common framing used for data blocks
// in text protocols such as SMTP.  The data consists of a sequence
// of lines, each of which ends in "\r\n".  The sequence itself
// ends at a line containing just a dot: ".\r\n".  Lines beginning
// with a dot are escaped with an additional dot to avoid
// looking like the end of the sequence.
//
// The decoded form returned by the Reader's Read method
// rewrites the "\r\n" line endings into the simpler "\n",
// removes leading dot escapes if present, and stops with error io.EOF
// after consuming (and discarding) the end-of-sequence line.
func ( *Reader) () io.Reader {
	.closeDot()
	.dot = &dotReader{r: }
	return .dot
}

type dotReader struct {
	r     *Reader
	state int
}

// Read satisfies reads by decoding dot-encoded data read from d.r.
func ( *dotReader) ( []byte) ( int,  error) {
	// Run data through a simple state machine to
	// elide leading dots, rewrite trailing \r\n into \n,
	// and detect ending .\r\n line.
	const (
		 = iota // beginning of line; initial state; must be zero
		              // read . at beginning of line
		            // read .\r at beginning of line
		               // read \r (possibly at end of line)
		             // reading data in middle of line
		              // reached .\r\n end marker line
	)
	 := .r.R
	for  < len() && .state !=  {
		var  byte
		,  = .ReadByte()
		if  != nil {
			if  == io.EOF {
				 = io.ErrUnexpectedEOF
			}
			break
		}
		switch .state {
		case :
			if  == '.' {
				.state = 
				continue
			}
			if  == '\r' {
				.state = 
				continue
			}
			.state = 

		case :
			if  == '\r' {
				.state = 
				continue
			}
			if  == '\n' {
				.state = 
				continue
			}
			.state = 

		case :
			if  == '\n' {
				.state = 
				continue
			}
			// Not part of .\r\n.
			// Consume leading dot and emit saved \r.
			.UnreadByte()
			 = '\r'
			.state = 

		case :
			if  == '\n' {
				.state = 
				break
			}
			// Not part of \r\n. Emit saved \r
			.UnreadByte()
			 = '\r'
			.state = 

		case :
			if  == '\r' {
				.state = 
				continue
			}
			if  == '\n' {
				.state = 
			}
		}
		[] = 
		++
	}
	if  == nil && .state ==  {
		 = io.EOF
	}
	if  != nil && .r.dot ==  {
		.r.dot = nil
	}
	return
}

// closeDot drains the current DotReader if any,
// making sure that it reads until the ending dot line.
func ( *Reader) () {
	if .dot == nil {
		return
	}
	 := make([]byte, 128)
	for .dot != nil {
		// When Read reaches EOF or an error,
		// it will set r.dot == nil.
		.dot.Read()
	}
}

// ReadDotBytes reads a dot-encoding and returns the decoded data.
//
// See the documentation for the DotReader method for details about dot-encoding.
func ( *Reader) () ([]byte, error) {
	return io.ReadAll(.DotReader())
}

// ReadDotLines reads a dot-encoding and returns a slice
// containing the decoded lines, with the final \r\n or \n elided from each.
//
// See the documentation for the DotReader method for details about dot-encoding.
func ( *Reader) () ([]string, error) {
	// We could use ReadDotBytes and then Split it,
	// but reading a line at a time avoids needing a
	// large contiguous block of memory and is simpler.
	var  []string
	var  error
	for {
		var  string
		,  = .ReadLine()
		if  != nil {
			if  == io.EOF {
				 = io.ErrUnexpectedEOF
			}
			break
		}

		// Dot by itself marks end; otherwise cut one dot.
		if len() > 0 && [0] == '.' {
			if len() == 1 {
				break
			}
			 = [1:]
		}
		 = append(, )
	}
	return , 
}

// ReadMIMEHeader reads a MIME-style header from r.
// The header is a sequence of possibly continued Key: Value lines
// ending in a blank line.
// The returned map m maps CanonicalMIMEHeaderKey(key) to a
// sequence of values in the same order encountered in the input.
//
// For example, consider this input:
//
//	My-Key: Value 1
//	Long-Key: Even
//	       Longer Value
//	My-Key: Value 2
//
// Given that input, ReadMIMEHeader returns the map:
//
//	map[string][]string{
//		"My-Key": {"Value 1", "Value 2"},
//		"Long-Key": {"Even Longer Value"},
//	}
//
func ( *Reader) () (MIMEHeader, error) {
	// Avoid lots of small slice allocations later by allocating one
	// large one ahead of time which we'll cut up into smaller
	// slices. If this isn't big enough later, we allocate small ones.
	var  []string
	 := .upcomingHeaderNewlines()
	if  > 0 {
		 = make([]string, )
	}

	 := make(MIMEHeader, )

	// The first line cannot start with a leading space.
	if ,  := .R.Peek(1);  == nil && ([0] == ' ' || [0] == '\t') {
		,  := .readLineSlice()
		if  != nil {
			return , 
		}
		return , ProtocolError("malformed MIME header initial line: " + string())
	}

	for {
		,  := .readContinuedLineSlice(mustHaveFieldNameColon)
		if len() == 0 {
			return , 
		}

		// Key ends at first colon.
		 := bytes.IndexByte(, ':')
		if  < 0 {
			return , ProtocolError("malformed MIME header line: " + string())
		}
		 := canonicalMIMEHeaderKey([:])

		// As per RFC 7230 field-name is a token, tokens consist of one or more chars.
		// We could return a ProtocolError here, but better to be liberal in what we
		// accept, so if we get an empty key, skip it.
		if  == "" {
			continue
		}

		// Skip initial spaces in value.
		++ // skip colon
		for  < len() && ([] == ' ' || [] == '\t') {
			++
		}
		 := string([:])

		 := []
		if  == nil && len() > 0 {
			// More than likely this will be a single-element key.
			// Most headers aren't multi-valued.
			// Set the capacity on strs[0] to 1, so any future append
			// won't extend the slice into the other strings.
			,  = [:1:1], [1:]
			[0] = 
			[] = 
		} else {
			[] = append(, )
		}

		if  != nil {
			return , 
		}
	}
}

// noValidation is a no-op validation func for readContinuedLineSlice
// that permits any lines.
func noValidation( []byte) error { return nil }

// mustHaveFieldNameColon ensures that, per RFC 7230, the
// field-name is on a single line, so the first line must
// contain a colon.
func mustHaveFieldNameColon( []byte) error {
	if bytes.IndexByte(, ':') < 0 {
		return ProtocolError(fmt.Sprintf("malformed MIME header: missing colon: %q", ))
	}
	return nil
}

// upcomingHeaderNewlines returns an approximation of the number of newlines
// that will be in this header. If it gets confused, it returns 0.
func ( *Reader) () ( int) {
	// Try to determine the 'hint' size.
	.R.Peek(1) // force a buffer load if empty
	 := .R.Buffered()
	if  == 0 {
		return
	}
	,  := .R.Peek()
	for len() > 0 {
		 := bytes.IndexByte(, '\n')
		if  < 3 {
			// Not present (-1) or found within the next few bytes,
			// implying we're at the end ("\r\n\r\n" or "\n\n")
			return
		}
		++
		 = [+1:]
	}
	return
}

// CanonicalMIMEHeaderKey returns the canonical format of the
// MIME header key s. The canonicalization converts the first
// letter and any letter following a hyphen to upper case;
// the rest are converted to lowercase. For example, the
// canonical key for "accept-encoding" is "Accept-Encoding".
// MIME header keys are assumed to be ASCII only.
// If s contains a space or invalid header field bytes, it is
// returned without modifications.
func ( string) string {
	commonHeaderOnce.Do(initCommonHeader)

	// Quick check for canonical encoding.
	 := true
	for  := 0;  < len(); ++ {
		 := []
		if !validHeaderFieldByte() {
			return 
		}
		if  && 'a' <=  &&  <= 'z' {
			return canonicalMIMEHeaderKey([]byte())
		}
		if ! && 'A' <=  &&  <= 'Z' {
			return canonicalMIMEHeaderKey([]byte())
		}
		 =  == '-'
	}
	return 
}

const toLower = 'a' - 'A'

// validHeaderFieldByte reports whether b is a valid byte in a header
// field name. RFC 7230 says:
//   header-field   = field-name ":" OWS field-value OWS
//   field-name     = token
//   tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
//           "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
//   token = 1*tchar
func validHeaderFieldByte( byte) bool {
	return int() < len(isTokenTable) && isTokenTable[]
}

// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
// allowed to mutate the provided byte slice before returning the
// string.
//
// For invalid inputs (if a contains spaces or non-token bytes), a
// is unchanged and a string copy is returned.
func canonicalMIMEHeaderKey( []byte) string {
	// See if a looks like a header key. If not, return it unchanged.
	for ,  := range  {
		if validHeaderFieldByte() {
			continue
		}
		// Don't canonicalize.
		return string()
	}

	 := true
	for ,  := range  {
		// Canonicalize: first letter upper case
		// and upper case after each dash.
		// (Host, User-Agent, If-Modified-Since).
		// MIME headers are ASCII only, so no Unicode issues.
		if  && 'a' <=  &&  <= 'z' {
			 -= toLower
		} else if ! && 'A' <=  &&  <= 'Z' {
			 += toLower
		}
		[] = 
		 =  == '-' // for next time
	}
	// The compiler recognizes m[string(byteSlice)] as a special
	// case, so a copy of a's bytes into a new string does not
	// happen in this map lookup:
	if  := commonHeader[string()];  != "" {
		return 
	}
	return string()
}

// commonHeader interns common header strings.
var commonHeader map[string]string

var commonHeaderOnce sync.Once

func initCommonHeader() {
	commonHeader = make(map[string]string)
	for ,  := range []string{
		"Accept",
		"Accept-Charset",
		"Accept-Encoding",
		"Accept-Language",
		"Accept-Ranges",
		"Cache-Control",
		"Cc",
		"Connection",
		"Content-Id",
		"Content-Language",
		"Content-Length",
		"Content-Transfer-Encoding",
		"Content-Type",
		"Cookie",
		"Date",
		"Dkim-Signature",
		"Etag",
		"Expires",
		"From",
		"Host",
		"If-Modified-Since",
		"If-None-Match",
		"In-Reply-To",
		"Last-Modified",
		"Location",
		"Message-Id",
		"Mime-Version",
		"Pragma",
		"Received",
		"Return-Path",
		"Server",
		"Set-Cookie",
		"Subject",
		"To",
		"User-Agent",
		"Via",
		"X-Forwarded-For",
		"X-Imforwards",
		"X-Powered-By",
	} {
		commonHeader[] = 
	}
}

// isTokenTable is a copy of net/http/lex.go's isTokenTable.
// See https://httpwg.github.io/specs/rfc7230.html#rule.token.separators
var isTokenTable = [127]bool{
	'!':  true,
	'#':  true,
	'$':  true,
	'%':  true,
	'&':  true,
	'\'': true,
	'*':  true,
	'+':  true,
	'-':  true,
	'.':  true,
	'0':  true,
	'1':  true,
	'2':  true,
	'3':  true,
	'4':  true,
	'5':  true,
	'6':  true,
	'7':  true,
	'8':  true,
	'9':  true,
	'A':  true,
	'B':  true,
	'C':  true,
	'D':  true,
	'E':  true,
	'F':  true,
	'G':  true,
	'H':  true,
	'I':  true,
	'J':  true,
	'K':  true,
	'L':  true,
	'M':  true,
	'N':  true,
	'O':  true,
	'P':  true,
	'Q':  true,
	'R':  true,
	'S':  true,
	'T':  true,
	'U':  true,
	'W':  true,
	'V':  true,
	'X':  true,
	'Y':  true,
	'Z':  true,
	'^':  true,
	'_':  true,
	'`':  true,
	'a':  true,
	'b':  true,
	'c':  true,
	'd':  true,
	'e':  true,
	'f':  true,
	'g':  true,
	'h':  true,
	'i':  true,
	'j':  true,
	'k':  true,
	'l':  true,
	'm':  true,
	'n':  true,
	'o':  true,
	'p':  true,
	'q':  true,
	'r':  true,
	's':  true,
	't':  true,
	'u':  true,
	'v':  true,
	'w':  true,
	'x':  true,
	'y':  true,
	'z':  true,
	'|':  true,
	'~':  true,
}