🏗️More into requests
Maps were way too expensive to work with. Linear search was the real winner.
Key-value storage
Headers, parameters, dynamic path wildcards, cookies — almost every key-value storage uses the same underlying implementation — *kv.Storage
. Which in fact makes life a bit easier: the same set of methods is available everywhere. Here's a quick demo of what we can actually do with the storage:
func myHandler(req *http.Request) *http.Response {
if !req.Headers.Has("some-header") {
return http.Error(req, status.ErrForbidden)
}
header, found := req.Headers.Lookup("some-header")
// or:
header = req.Headers.Value("some-header")
// get all the header values:
values := slices.Collect(req.Headers.Values("some-header"))
// get all the headers names contained:
keys := slices.Collect(req.Headers.Keys())
// headers object will be re-used on a next request.
// To use it after current request is processed,
// you must clone it:
headersCopy := req.Headers.Clone()
// ...and a plenty of others, whose names are pretty
// self-describing. Sorry:(
}
There's slices.Collect()
used on some calls. That's because otherwise we would need to store and handle countless buffers, so instead iterators are returned.
Hijacking
Hijacking a connection returns the net.Client
, which wraps the connection, and an error. An error is returned, because during the hijacking the request's body is drained automatically. The reason hjiacking returns the net.Client
is, it implements a pushback - extra data read from the connection is stored back in order to be read the next time.
func hijacker(request *http.Request) *http.Response {
client, err := request.Hijack()
if err != nil {
return http.Error(request, err)
}
pending := client.Pending()
conn := client.Conn()
...
return nil
}
Please, note that there is no need to close the connection. It'll be closed automatically as the handler exits.
Last updated