1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
|
<h1> Package textproto </h1> <ul id="short-nav">
<li><code>import "net/textproto"</code></li>
<li><a href="#pkg-overview" class="overviewLink">Overview</a></li>
<li><a href="#pkg-index" class="indexLink">Index</a></li>
</ul> <h2 id="pkg-overview">Overview </h2> <p>Package textproto implements generic support for text-based request/response protocols in the style of HTTP, NNTP, and SMTP. </p>
<p>The package provides: </p>
<p><a href="#Error">Error</a>, which represents a numeric error response from a server. </p>
<p><a href="#Pipeline">Pipeline</a>, to manage pipelined requests and responses in a client. </p>
<p><a href="#Reader">Reader</a>, to read numeric response code lines, key: value headers, lines wrapped with leading spaces on continuation lines, and whole text blocks ending with a dot on a line by itself. </p>
<p><a href="#Writer">Writer</a>, to write dot-encoded text blocks. </p>
<p><a href="#Conn">Conn</a>, a convenient packaging of <a href="#Reader">Reader</a>, <a href="#Writer">Writer</a>, and <a href="#Pipeline">Pipeline</a> for use with a single network connection. </p> <h2 id="pkg-index">Index </h2> <ul id="manual-nav">
<li><a href="#CanonicalMIMEHeaderKey">func CanonicalMIMEHeaderKey(s string) string</a></li>
<li><a href="#TrimBytes">func TrimBytes(b []byte) []byte</a></li>
<li><a href="#TrimString">func TrimString(s string) string</a></li>
<li><a href="#Conn">type Conn</a></li>
<li> <a href="#Dial">func Dial(network, addr string) (*Conn, error)</a>
</li>
<li> <a href="#NewConn">func NewConn(conn io.ReadWriteCloser) *Conn</a>
</li>
<li> <a href="#Conn.Close">func (c *Conn) Close() error</a>
</li>
<li> <a href="#Conn.Cmd">func (c *Conn) Cmd(format string, args ...any) (id uint, err error)</a>
</li>
<li><a href="#Error">type Error</a></li>
<li> <a href="#Error.Error">func (e *Error) Error() string</a>
</li>
<li><a href="#MIMEHeader">type MIMEHeader</a></li>
<li> <a href="#MIMEHeader.Add">func (h MIMEHeader) Add(key, value string)</a>
</li>
<li> <a href="#MIMEHeader.Del">func (h MIMEHeader) Del(key string)</a>
</li>
<li> <a href="#MIMEHeader.Get">func (h MIMEHeader) Get(key string) string</a>
</li>
<li> <a href="#MIMEHeader.Set">func (h MIMEHeader) Set(key, value string)</a>
</li>
<li> <a href="#MIMEHeader.Values">func (h MIMEHeader) Values(key string) []string</a>
</li>
<li><a href="#Pipeline">type Pipeline</a></li>
<li> <a href="#Pipeline.EndRequest">func (p *Pipeline) EndRequest(id uint)</a>
</li>
<li> <a href="#Pipeline.EndResponse">func (p *Pipeline) EndResponse(id uint)</a>
</li>
<li> <a href="#Pipeline.Next">func (p *Pipeline) Next() uint</a>
</li>
<li> <a href="#Pipeline.StartRequest">func (p *Pipeline) StartRequest(id uint)</a>
</li>
<li> <a href="#Pipeline.StartResponse">func (p *Pipeline) StartResponse(id uint)</a>
</li>
<li><a href="#ProtocolError">type ProtocolError</a></li>
<li> <a href="#ProtocolError.Error">func (p ProtocolError) Error() string</a>
</li>
<li><a href="#Reader">type Reader</a></li>
<li> <a href="#NewReader">func NewReader(r *bufio.Reader) *Reader</a>
</li>
<li> <a href="#Reader.DotReader">func (r *Reader) DotReader() io.Reader</a>
</li>
<li> <a href="#Reader.ReadCodeLine">func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error)</a>
</li>
<li> <a href="#Reader.ReadContinuedLine">func (r *Reader) ReadContinuedLine() (string, error)</a>
</li>
<li> <a href="#Reader.ReadContinuedLineBytes">func (r *Reader) ReadContinuedLineBytes() ([]byte, error)</a>
</li>
<li> <a href="#Reader.ReadDotBytes">func (r *Reader) ReadDotBytes() ([]byte, error)</a>
</li>
<li> <a href="#Reader.ReadDotLines">func (r *Reader) ReadDotLines() ([]string, error)</a>
</li>
<li> <a href="#Reader.ReadLine">func (r *Reader) ReadLine() (string, error)</a>
</li>
<li> <a href="#Reader.ReadLineBytes">func (r *Reader) ReadLineBytes() ([]byte, error)</a>
</li>
<li> <a href="#Reader.ReadMIMEHeader">func (r *Reader) ReadMIMEHeader() (MIMEHeader, error)</a>
</li>
<li> <a href="#Reader.ReadResponse">func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error)</a>
</li>
<li><a href="#Writer">type Writer</a></li>
<li> <a href="#NewWriter">func NewWriter(w *bufio.Writer) *Writer</a>
</li>
<li> <a href="#Writer.DotWriter">func (w *Writer) DotWriter() io.WriteCloser</a>
</li>
<li> <a href="#Writer.PrintfLine">func (w *Writer) PrintfLine(format string, args ...any) error</a>
</li>
</ul> <h3>Package files</h3> <p> <span>header.go</span> <span>pipeline.go</span> <span>reader.go</span> <span>textproto.go</span> <span>writer.go</span> </p> <h2 id="CanonicalMIMEHeaderKey">func <span>CanonicalMIMEHeaderKey</span> </h2> <pre data-language="go">func CanonicalMIMEHeaderKey(s string) string</pre> <p>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. </p>
<h2 id="TrimBytes">func <span>TrimBytes</span> <span title="Added in Go 1.1">1.1</span> </h2> <pre data-language="go">func TrimBytes(b []byte) []byte</pre> <p>TrimBytes returns b without leading and trailing ASCII space. </p>
<h2 id="TrimString">func <span>TrimString</span> <span title="Added in Go 1.1">1.1</span> </h2> <pre data-language="go">func TrimString(s string) string</pre> <p>TrimString returns s without leading and trailing ASCII space. </p>
<h2 id="Conn">type <span>Conn</span> </h2> <p>A Conn represents a textual network protocol connection. It consists of a <a href="#Reader">Reader</a> and <a href="#Writer">Writer</a> to manage I/O and a <a href="#Pipeline">Pipeline</a> to sequence concurrent requests on the connection. These embedded types carry methods with them; see the documentation of those types for details. </p>
<pre data-language="go">type Conn struct {
Reader
Writer
Pipeline
// contains filtered or unexported fields
}
</pre> <h3 id="Dial">func <span>Dial</span> </h3> <pre data-language="go">func Dial(network, addr string) (*Conn, error)</pre> <p>Dial connects to the given address on the given network using <span>net.Dial</span> and then returns a new <a href="#Conn">Conn</a> for the connection. </p>
<h3 id="NewConn">func <span>NewConn</span> </h3> <pre data-language="go">func NewConn(conn io.ReadWriteCloser) *Conn</pre> <p>NewConn returns a new <a href="#Conn">Conn</a> using conn for I/O. </p>
<h3 id="Conn.Close">func (*Conn) <span>Close</span> </h3> <pre data-language="go">func (c *Conn) Close() error</pre> <p>Close closes the connection. </p>
<h3 id="Conn.Cmd">func (*Conn) <span>Cmd</span> </h3> <pre data-language="go">func (c *Conn) Cmd(format string, args ...any) (id uint, err error)</pre> <p>Cmd is a convenience method that sends a command after waiting its turn in the pipeline. The command text is the result of formatting format with args and appending \r\n. Cmd returns the id of the command, for use with StartResponse and EndResponse. </p>
<p>For example, a client might run a HELP command that returns a dot-body by using: </p>
<pre data-language="go">id, err := c.Cmd("HELP")
if err != nil {
return nil, err
}
c.StartResponse(id)
defer c.EndResponse(id)
if _, _, err = c.ReadCodeLine(110); err != nil {
return nil, err
}
text, err := c.ReadDotBytes()
if err != nil {
return nil, err
}
return c.ReadCodeLine(250)
</pre> <h2 id="Error">type <span>Error</span> </h2> <p>An Error represents a numeric error response from a server. </p>
<pre data-language="go">type Error struct {
Code int
Msg string
}
</pre> <h3 id="Error.Error">func (*Error) <span>Error</span> </h3> <pre data-language="go">func (e *Error) Error() string</pre> <h2 id="MIMEHeader">type <span>MIMEHeader</span> </h2> <p>A MIMEHeader represents a MIME-style header mapping keys to sets of values. </p>
<pre data-language="go">type MIMEHeader map[string][]string</pre> <h3 id="MIMEHeader.Add">func (MIMEHeader) <span>Add</span> </h3> <pre data-language="go">func (h MIMEHeader) Add(key, value string)</pre> <p>Add adds the key, value pair to the header. It appends to any existing values associated with key. </p>
<h3 id="MIMEHeader.Del">func (MIMEHeader) <span>Del</span> </h3> <pre data-language="go">func (h MIMEHeader) Del(key string)</pre> <p>Del deletes the values associated with key. </p>
<h3 id="MIMEHeader.Get">func (MIMEHeader) <span>Get</span> </h3> <pre data-language="go">func (h MIMEHeader) Get(key string) string</pre> <p>Get gets the first value associated with the given key. It is case insensitive; <a href="#CanonicalMIMEHeaderKey">CanonicalMIMEHeaderKey</a> is used to canonicalize the provided key. If there are no values associated with the key, Get returns "". To use non-canonical keys, access the map directly. </p>
<h3 id="MIMEHeader.Set">func (MIMEHeader) <span>Set</span> </h3> <pre data-language="go">func (h MIMEHeader) Set(key, value string)</pre> <p>Set sets the header entries associated with key to the single element value. It replaces any existing values associated with key. </p>
<h3 id="MIMEHeader.Values">func (MIMEHeader) <span>Values</span> <span title="Added in Go 1.14">1.14</span> </h3> <pre data-language="go">func (h MIMEHeader) Values(key string) []string</pre> <p>Values returns all values associated with the given key. It is case insensitive; <a href="#CanonicalMIMEHeaderKey">CanonicalMIMEHeaderKey</a> is used to canonicalize the provided key. To use non-canonical keys, access the map directly. The returned slice is not a copy. </p>
<h2 id="Pipeline">type <span>Pipeline</span> </h2> <p>A Pipeline manages a pipelined in-order request/response sequence. </p>
<p>To use a Pipeline p to manage multiple clients on a connection, each client should run: </p>
<pre data-language="go">id := p.Next() // take a number
p.StartRequest(id) // wait for turn to send request
«send request»
p.EndRequest(id) // notify Pipeline that request is sent
p.StartResponse(id) // wait for turn to read response
«read response»
p.EndResponse(id) // notify Pipeline that response is read
</pre> <p>A pipelined server can use the same calls to ensure that responses computed in parallel are written in the correct order. </p>
<pre data-language="go">type Pipeline struct {
// contains filtered or unexported fields
}
</pre> <h3 id="Pipeline.EndRequest">func (*Pipeline) <span>EndRequest</span> </h3> <pre data-language="go">func (p *Pipeline) EndRequest(id uint)</pre> <p>EndRequest notifies p that the request with the given id has been sent (or, if this is a server, received). </p>
<h3 id="Pipeline.EndResponse">func (*Pipeline) <span>EndResponse</span> </h3> <pre data-language="go">func (p *Pipeline) EndResponse(id uint)</pre> <p>EndResponse notifies p that the response with the given id has been received (or, if this is a server, sent). </p>
<h3 id="Pipeline.Next">func (*Pipeline) <span>Next</span> </h3> <pre data-language="go">func (p *Pipeline) Next() uint</pre> <p>Next returns the next id for a request/response pair. </p>
<h3 id="Pipeline.StartRequest">func (*Pipeline) <span>StartRequest</span> </h3> <pre data-language="go">func (p *Pipeline) StartRequest(id uint)</pre> <p>StartRequest blocks until it is time to send (or, if this is a server, receive) the request with the given id. </p>
<h3 id="Pipeline.StartResponse">func (*Pipeline) <span>StartResponse</span> </h3> <pre data-language="go">func (p *Pipeline) StartResponse(id uint)</pre> <p>StartResponse blocks until it is time to receive (or, if this is a server, send) the request with the given id. </p>
<h2 id="ProtocolError">type <span>ProtocolError</span> </h2> <p>A ProtocolError describes a protocol violation such as an invalid response or a hung-up connection. </p>
<pre data-language="go">type ProtocolError string</pre> <h3 id="ProtocolError.Error">func (ProtocolError) <span>Error</span> </h3> <pre data-language="go">func (p ProtocolError) Error() string</pre> <h2 id="Reader">type <span>Reader</span> </h2> <p>A Reader implements convenience methods for reading requests or responses from a text protocol network connection. </p>
<pre data-language="go">type Reader struct {
R *bufio.Reader
// contains filtered or unexported fields
}
</pre> <h3 id="NewReader">func <span>NewReader</span> </h3> <pre data-language="go">func NewReader(r *bufio.Reader) *Reader</pre> <p>NewReader returns a new <a href="#Reader">Reader</a> reading from r. </p>
<p>To avoid denial of service attacks, the provided <span>bufio.Reader</span> should be reading from an <span>io.LimitReader</span> or similar Reader to bound the size of responses. </p>
<h3 id="Reader.DotReader">func (*Reader) <span>DotReader</span> </h3> <pre data-language="go">func (r *Reader) DotReader() io.Reader</pre> <p>DotReader returns a new <a href="#Reader">Reader</a> 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. </p>
<p>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. </p>
<p>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 <span>io.EOF</span> after consuming (and discarding) the end-of-sequence line. </p>
<h3 id="Reader.ReadCodeLine">func (*Reader) <span>ReadCodeLine</span> </h3> <pre data-language="go">func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error)</pre> <p>ReadCodeLine reads a response code line of the form </p>
<pre data-language="go">code message
</pre> <p>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: </p>
<pre data-language="go">220 plan9.bell-labs.com ESMTP
</pre> <p>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]. </p>
<p>If the response is multi-line, ReadCodeLine returns an error. </p>
<p>An expectCode <= 0 disables the check of the status code. </p>
<h3 id="Reader.ReadContinuedLine">func (*Reader) <span>ReadContinuedLine</span> </h3> <pre data-language="go">func (r *Reader) ReadContinuedLine() (string, error)</pre> <p>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. </p>
<p>For example, consider this input: </p>
<pre data-language="go">Line 1
continued...
Line 2
</pre> <p>The first call to ReadContinuedLine will return "Line 1 continued..." and the second will return "Line 2". </p>
<p>Empty lines are never continued. </p>
<h3 id="Reader.ReadContinuedLineBytes">func (*Reader) <span>ReadContinuedLineBytes</span> </h3> <pre data-language="go">func (r *Reader) ReadContinuedLineBytes() ([]byte, error)</pre> <p>ReadContinuedLineBytes is like <a href="#Reader.ReadContinuedLine">Reader.ReadContinuedLine</a> but returns a []byte instead of a string. </p>
<h3 id="Reader.ReadDotBytes">func (*Reader) <span>ReadDotBytes</span> </h3> <pre data-language="go">func (r *Reader) ReadDotBytes() ([]byte, error)</pre> <p>ReadDotBytes reads a dot-encoding and returns the decoded data. </p>
<p>See the documentation for the <a href="#Reader.DotReader">Reader.DotReader</a> method for details about dot-encoding. </p>
<h3 id="Reader.ReadDotLines">func (*Reader) <span>ReadDotLines</span> </h3> <pre data-language="go">func (r *Reader) ReadDotLines() ([]string, error)</pre> <p>ReadDotLines reads a dot-encoding and returns a slice containing the decoded lines, with the final \r\n or \n elided from each. </p>
<p>See the documentation for the <a href="#Reader.DotReader">Reader.DotReader</a> method for details about dot-encoding. </p>
<h3 id="Reader.ReadLine">func (*Reader) <span>ReadLine</span> </h3> <pre data-language="go">func (r *Reader) ReadLine() (string, error)</pre> <p>ReadLine reads a single line from r, eliding the final \n or \r\n from the returned string. </p>
<h3 id="Reader.ReadLineBytes">func (*Reader) <span>ReadLineBytes</span> </h3> <pre data-language="go">func (r *Reader) ReadLineBytes() ([]byte, error)</pre> <p>ReadLineBytes is like <a href="#Reader.ReadLine">Reader.ReadLine</a> but returns a []byte instead of a string. </p>
<h3 id="Reader.ReadMIMEHeader">func (*Reader) <span>ReadMIMEHeader</span> </h3> <pre data-language="go">func (r *Reader) ReadMIMEHeader() (MIMEHeader, error)</pre> <p>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 <a href="#CanonicalMIMEHeaderKey">CanonicalMIMEHeaderKey</a>(key) to a sequence of values in the same order encountered in the input. </p>
<p>For example, consider this input: </p>
<pre data-language="go">My-Key: Value 1
Long-Key: Even
Longer Value
My-Key: Value 2
</pre> <p>Given that input, ReadMIMEHeader returns the map: </p>
<pre data-language="go">map[string][]string{
"My-Key": {"Value 1", "Value 2"},
"Long-Key": {"Even Longer Value"},
}
</pre> <h3 id="Reader.ReadResponse">func (*Reader) <span>ReadResponse</span> </h3> <pre data-language="go">func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error)</pre> <p>ReadResponse reads a multi-line response of the form: </p>
<pre data-language="go">code-message line 1
code-message line 2
...
code message line n
</pre> <p>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). </p>
<p>See page 36 of RFC 959 (<a href="https://www.ietf.org/rfc/rfc959.txt">https://www.ietf.org/rfc/rfc959.txt</a>) for details of another form of response accepted: </p>
<pre data-language="go">code-message line 1
message line 2
...
code message line n
</pre> <p>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]. </p>
<p>An expectCode <= 0 disables the check of the status code. </p>
<h2 id="Writer">type <span>Writer</span> </h2> <p>A Writer implements convenience methods for writing requests or responses to a text protocol network connection. </p>
<pre data-language="go">type Writer struct {
W *bufio.Writer
// contains filtered or unexported fields
}
</pre> <h3 id="NewWriter">func <span>NewWriter</span> </h3> <pre data-language="go">func NewWriter(w *bufio.Writer) *Writer</pre> <p>NewWriter returns a new <a href="#Writer">Writer</a> writing to w. </p>
<h3 id="Writer.DotWriter">func (*Writer) <span>DotWriter</span> </h3> <pre data-language="go">func (w *Writer) DotWriter() io.WriteCloser</pre> <p>DotWriter returns a writer that can be used to write a dot-encoding to w. It takes care of inserting leading dots when necessary, translating line-ending \n into \r\n, and adding the final .\r\n line when the DotWriter is closed. The caller should close the DotWriter before the next call to a method on w. </p>
<p>See the documentation for the <a href="#Reader.DotReader">Reader.DotReader</a> method for details about dot-encoding. </p>
<h3 id="Writer.PrintfLine">func (*Writer) <span>PrintfLine</span> </h3> <pre data-language="go">func (w *Writer) PrintfLine(format string, args ...any) error</pre> <p>PrintfLine writes the formatted output followed by \r\n. </p><div class="_attribution">
<p class="_attribution-p">
© Google, Inc.<br>Licensed under the Creative Commons Attribution License 3.0.<br>
<a href="http://golang.org/pkg/net/textproto/" class="_attribution-link">http://golang.org/pkg/net/textproto/</a>
</p>
</div>
|