aboutsummaryrefslogtreecommitdiff
path: root/response.go
diff options
context:
space:
mode:
authorAdnan Maolood <[email protected]>2020-10-21 17:07:28 -0400
committerAdnan Maolood <[email protected]>2020-10-21 17:07:28 -0400
commit9506f69f1aef8722f06bb47d65f99ff0bffb7347 (patch)
tree35fec7ce8ecb79c758f01d9d48550945b845e2e8 /response.go
parentRename Handler to Responder (diff)
downloadgo-gemini-9506f69f1aef8722f06bb47d65f99ff0bffb7347.tar.xz
go-gemini-9506f69f1aef8722f06bb47d65f99ff0bffb7347.zip
Refactor
Diffstat (limited to 'response.go')
-rw-r--r--response.go85
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
+}