summaryrefslogtreecommitdiff
path: root/internal
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-08-12 09:40:39 -0600
committertjpcc <tjp@ctrl-c.club>2023-08-12 09:40:39 -0600
commit23bc5f4fb7542e64c94eaa7fe2c7a6aa55010898 (patch)
treeec8113d3aa2379e3ca9cb3c6e13a5531895ea8c0 /internal
parent57a31a9b2cd549174d839b9b91b47db337f174cc (diff)
move common types to an internal package
This helps avoid import cycles.
Diffstat (limited to 'internal')
-rw-r--r--internal/types/handler.go28
-rw-r--r--internal/types/request.go49
-rw-r--r--internal/types/response.go35
-rw-r--r--internal/types/server.go42
4 files changed, 154 insertions, 0 deletions
diff --git a/internal/types/handler.go b/internal/types/handler.go
new file mode 100644
index 0000000..4805c57
--- /dev/null
+++ b/internal/types/handler.go
@@ -0,0 +1,28 @@
+package types
+
+import "context"
+
+// Handler is a type which can turn a request into a response.
+//
+// Handle may return a nil response, in which case the Server is expected
+// to build the protocol-appropriate "Not Found" response.
+type Handler interface {
+ Handle(context.Context, *Request) *Response
+}
+
+// Middleware is a handler decorator.
+//
+// It returns a handler which may call the passed-in handler or not, or may
+// transform the request or response in some way.
+type Middleware func(Handler) Handler
+
+func HandlerFunc(f func(context.Context, *Request) *Response) Handler {
+ return handlerFunc(f)
+}
+
+// Handle implements Handler.
+func (f handlerFunc) Handle(ctx context.Context, request *Request) *Response {
+ return f(ctx, request)
+}
+
+type handlerFunc func(context.Context, *Request) *Response
diff --git a/internal/types/request.go b/internal/types/request.go
new file mode 100644
index 0000000..e3d2e6f
--- /dev/null
+++ b/internal/types/request.go
@@ -0,0 +1,49 @@
+package types
+
+import (
+ "crypto/tls"
+ "net"
+ "net/url"
+)
+
+// Request represents a request over any small web protocol.
+//
+// Because protocols have so many differences, this type represents a
+// greatest common denominator of request/response-oriented protocols.
+type Request struct {
+ // URL is the specific URL being fetched by the request.
+ *url.URL
+
+ // Server is the server which received the request.
+ //
+ // This is only populated in servers.
+ // It is unused on the client end.
+ Server Server
+
+ // Meta is a place for opaque data.
+ //
+ // Look for helper methods in protocol packages to use it appropriately
+ // for the protocol.
+ Meta any
+
+ // RemoteAddr is the address of the other side of the connection.
+ //
+ // This will be the server address for clients, or the connecting
+ // client's address in servers.
+ //
+ // Be aware though that proxies (and reverse proxies) can confuse this.
+ RemoteAddr net.Addr
+
+ // TLSState contains information about the TLS encryption over the connection.
+ //
+ // This includes peer certificates and version information.
+ TLSState *tls.ConnectionState
+}
+
+// UnescapedQuery performs %XX unescaping on the URL query segment.
+//
+// Like URL.Query(), it silently drops malformed %-encoded sequences.
+func (req Request) UnescapedQuery() string {
+ unescaped, _ := url.QueryUnescape(req.RawQuery)
+ return unescaped
+}
diff --git a/internal/types/response.go b/internal/types/response.go
new file mode 100644
index 0000000..26dda05
--- /dev/null
+++ b/internal/types/response.go
@@ -0,0 +1,35 @@
+package types
+
+import "io"
+
+// Status is the integer status code of a response.
+type Status int
+
+// Response contains the data in a response over the small web.
+//
+// Because protocols have so many differences, this type represents a
+// greatest common denominator of request/response-oriented protocols.
+type Response struct {
+ // Status is the status code of the response.
+ Status Status
+
+ // Meta contains status-specific additional information.
+ Meta any
+
+ // Body is the response body, if any.
+ Body io.Reader
+}
+
+func (response *Response) Close() error {
+ if cl, ok := response.Body.(io.Closer); ok {
+ return cl.Close()
+ }
+ return nil
+}
+
+// ResponseReader is an object which can serialize a response to a protocol.
+type ResponseReader interface {
+ io.Reader
+ io.WriterTo
+ io.Closer
+}
diff --git a/internal/types/server.go b/internal/types/server.go
new file mode 100644
index 0000000..80d12b5
--- /dev/null
+++ b/internal/types/server.go
@@ -0,0 +1,42 @@
+package types
+
+// Server is a type which can serve a protocol.
+type Server interface {
+ // Serve blocks listening for connections on an interface.
+ //
+ // It will only return after Close() has been called.
+ Serve() error
+
+ // Close initiates a graceful shutdown of the server.
+ //
+ // It blocks until all resources have been cleaned up and all
+ // outstanding requests have been handled and responses sent.
+ Close()
+
+ // Closed indicates whether Close has been called.
+ //
+ // It may be true even if the graceful shutdown procedure
+ // hasn't yet completed.
+ Closed() bool
+
+ // Protocol returns the protocol being served by the server.
+ Protocol() string
+
+ // Network returns the network type on which the server is running.
+ Network() string
+
+ // Address returns the address on which the server is listening.
+ Address() string
+
+ // Hostname returns just the hostname portion of the listen address.
+ Hostname() string
+
+ // Port returns the port on which the server is listening.
+ //
+ // It will return the empty string if the network type does not
+ // have ports (unix sockets, for example).
+ Port() string
+
+ // LogError sends a log message to the server's error log.
+ LogError(keyvals ...any) error
+}