diff options
author | tjpcc <tjp@ctrl-c.club> | 2023-08-12 09:40:39 -0600 |
---|---|---|
committer | tjpcc <tjp@ctrl-c.club> | 2023-08-12 09:40:39 -0600 |
commit | 23bc5f4fb7542e64c94eaa7fe2c7a6aa55010898 (patch) | |
tree | ec8113d3aa2379e3ca9cb3c6e13a5531895ea8c0 /internal/types | |
parent | 57a31a9b2cd549174d839b9b91b47db337f174cc (diff) |
move common types to an internal package
This helps avoid import cycles.
Diffstat (limited to 'internal/types')
-rw-r--r-- | internal/types/handler.go | 28 | ||||
-rw-r--r-- | internal/types/request.go | 49 | ||||
-rw-r--r-- | internal/types/response.go | 35 | ||||
-rw-r--r-- | internal/types/server.go | 42 |
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 +} |