diff options
| author | Adnan Maolood <[email protected]> | 2020-10-21 17:07:28 -0400 |
|---|---|---|
| committer | Adnan Maolood <[email protected]> | 2020-10-21 17:07:28 -0400 |
| commit | 9506f69f1aef8722f06bb47d65f99ff0bffb7347 (patch) | |
| tree | 35fec7ce8ecb79c758f01d9d48550945b845e2e8 /response.go | |
| parent | Rename Handler to Responder (diff) | |
| download | go-gemini-9506f69f1aef8722f06bb47d65f99ff0bffb7347.tar.xz go-gemini-9506f69f1aef8722f06bb47d65f99ff0bffb7347.zip | |
Refactor
Diffstat (limited to 'response.go')
| -rw-r--r-- | response.go | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/response.go b/response.go new file mode 100644 index 0000000..975425a --- /dev/null +++ b/response.go @@ -0,0 +1,85 @@ +package gmi + +import ( + "bufio" + "crypto/tls" + "io/ioutil" + "strconv" +) + +// Response is a Gemini response. +type Response struct { + // Status represents the response status. + Status int + + // Meta contains more information related to the response status. + // For successful responses, Meta should contain the mimetype of the response. + // For failure responses, Meta should contain a short description of the failure. + // Meta should not be longer than 1024 bytes. + Meta string + + // Body contains the response body. + Body []byte + + // TLS contains information about the TLS connection on which the response + // was received. + TLS tls.ConnectionState +} + +// read reads a Gemini response from the provided buffered reader. +func (resp *Response) read(r *bufio.Reader) error { + // Read the status + statusB := make([]byte, 2) + if _, err := r.Read(statusB); err != nil { + return err + } + status, err := strconv.Atoi(string(statusB)) + if err != nil { + return err + } + resp.Status = status + + // Disregard invalid status codes + const minStatus, maxStatus = 1, 6 + statusClass := status / 10 + if statusClass < minStatus || statusClass > maxStatus { + return ErrInvalidResponse + } + + // Read one space + if b, err := r.ReadByte(); err != nil { + return err + } else if b != ' ' { + return ErrInvalidResponse + } + + // Read the meta + meta, err := r.ReadString('\r') + if err != nil { + return err + } + // Trim carriage return + meta = meta[:len(meta)-1] + // Ensure meta is less than or equal to 1024 bytes + if len(meta) > 1024 { + return ErrInvalidResponse + } + resp.Meta = meta + + // Read terminating newline + if b, err := r.ReadByte(); err != nil { + return err + } else if b != '\n' { + return ErrInvalidResponse + } + + // Read response body + if status/10 == StatusClassSuccess { + var err error + resp.Body, err = ioutil.ReadAll(r) + if err != nil { + return err + } + } + return nil +} |