@@ -2,17 +2,19 @@ package chain
22
33import (
44 "context"
5- "github.com/segmentio/ksuid"
65 "net/http"
76 "strings"
8- "time"
97)
108
119type chainContextKey struct {}
10+ type bodyBytesKey struct {}
1211
1312// ContextKey is the request context key under which URL params are stored.
1413var ContextKey = chainContextKey {}
1514
15+ // BodyBytesKey indicates a default body bytes key.
16+ var BodyBytesKey = bodyBytesKey {}
17+
1618// GetContext pulls the URL parameters from a request context, or returns nil if none are present.
1719func GetContext (ctx context.Context ) * Context {
1820 p , _ := ctx .Value (ContextKey ).(* Context )
@@ -33,7 +35,7 @@ type Context struct {
3335 MatchedRoutePath string
3436 Writer http.ResponseWriter
3537 Request * http.Request
36- Crypto * cryptoShortcuts
38+ Crypto * cryptoImpl
3739 root * Context
3840 children []* Context
3941}
@@ -50,41 +52,16 @@ func (ctx *Context) Set(key any, value any) {
5052}
5153
5254// Get obtém um valor compartilhado no contexto de execução da requisição
53- func (ctx * Context ) Get (key any ) any {
55+ func (ctx * Context ) Get (key any ) ( any , bool ) {
5456 if ctx .root != nil {
5557 return ctx .root .Get (key )
5658 }
5759
5860 if ctx .data == nil {
59- return nil
60- }
61- if value , exists := ctx .data [key ]; exists {
62- return value
63- }
64- return nil
65- }
66-
67- // GetParam returns the value of the first Param which key matches the given name.
68- // If no matching Param is found, an empty string is returned.
69- func (ctx * Context ) GetParam (name string ) string {
70- for i := 0 ; i < ctx .paramCount ; i ++ {
71- if ctx .paramNames [i ] == name {
72- return ctx .paramValues [i ]
73- }
61+ return nil , false
7462 }
75- return ""
76- }
77-
78- // GetParamByIndex get one parameter per index
79- func (ctx * Context ) GetParamByIndex (index int ) string {
80- return ctx .paramValues [index ]
81- }
82-
83- // addParameter adds a new parameter to the Context.
84- func (ctx * Context ) addParameter (name string , value string ) {
85- ctx .paramNames [ctx .paramCount ] = name
86- ctx .paramValues [ctx .paramCount ] = value
87- ctx .paramCount ++
63+ value , exists := ctx .data [key ]
64+ return value , exists
8865}
8966
9067func (ctx * Context ) WithParams (names []string , values []string ) * Context {
@@ -120,193 +97,51 @@ func (ctx *Context) WithParams(names []string, values []string) *Context {
12097 return child
12198}
12299
123- // Router get current router reference
124- func (ctx * Context ) Router () * Router {
125- return ctx .router
126- }
127-
128- // Header returns the header map that will be sent by
129- // WriteHeader. The Header map also is the mechanism with which
130- // Handlers can set HTTP trailers.
131- //
132- // Changing the header map after a call to WriteHeader (or
133- // Write) has no effect unless the HTTP status code was of the
134- // 1xx class or the modified headers are trailers.
135- //
136- // There are two ways to set Trailers. The preferred way is to
137- // predeclare in the headers which trailers you will later
138- // send by setting the "Trailer" header to the names of the
139- // trailer keys which will come later. In this case, those
140- // keys of the Header map are treated as if they were
141- // trailers. See the example. The second way, for trailer
142- // keys not known to the Handle until after the first Write,
143- // is to prefix the Header map keys with the TrailerPrefix
144- // constant value. See TrailerPrefix.
145- //
146- // To suppress automatic response headers (such as "Date"), set
147- // their value to nil.
148- func (ctx * Context ) Header () http.Header {
149- return ctx .Writer .Header ()
150- }
151-
152- // SetHeader sets the header entries associated with key to the single element value. It replaces any existing values
153- // associated with key. The key is case insensitive; it is canonicalized by textproto.CanonicalMIMEHeaderKey.
154- // To use non-canonical keys, assign to the map directly.
155- func (ctx * Context ) SetHeader (key , value string ) {
156- ctx .Writer .Header ().Set (key , value )
157- }
158-
159- // AddHeader adds the key, value pair to the header.
160- // It appends to any existing values associated with key.
161- // The key is case insensitive; it is canonicalized by CanonicalHeaderKey.
162- func (ctx * Context ) AddHeader (key , value string ) {
163- ctx .Writer .Header ().Add (key , value )
164- }
165-
166- // GetHeader gets the first value associated with the given key. If there are no values associated with the key,
167- // GetHeader returns "".
168- // It is case insensitive; textproto.CanonicalMIMEHeaderKey is used to canonicalize the provided key. Get assumes
169- // that all keys are stored in canonical form. To use non-canonical keys, access the map directly.
170- func (ctx * Context ) GetHeader (key string ) string {
171- return ctx .Writer .Header ().Get (key )
172- }
173-
174- // Error replies to the request with the specified error message and HTTP code.
175- // It does not otherwise end the request; the caller should ensure no further writes are done to w.
176- // The error message should be plain text.
177- func (ctx * Context ) Error (error string , code int ) {
178- http .Error (ctx .Writer , error , code )
179- }
180-
181- // NotFound replies to the request with an HTTP 404 not found error.
182- func (ctx * Context ) NotFound () {
183- http .NotFound (ctx .Writer , ctx .Request )
184- }
185-
186- // Redirect replies to the request with a redirect to url, which may be a path relative to the request path.
187- //
188- // The provided code should be in the 3xx range and is usually StatusMovedPermanently, StatusFound or StatusSeeOther.
189- //
190- // If the Content-Type header has not been set, Redirect sets it to "text/html; charset=utf-8" and writes a small HTML
191- // body.
192- //
193- // Setting the Content-Type header to any value, including nil, disables that behavior.
194- func (ctx * Context ) Redirect (url string , code int ) {
195- http .Redirect (ctx .Writer , ctx .Request , url , code )
196- }
197-
198- // Write writes the data to the connection as part of an HTTP reply.
199- //
200- // If WriteHeader has not yet been called, Write calls
201- // WriteHeader(http.StatusOK) before writing the data. If the Header
202- // does not contain a Content-Type line, Write adds a Content-Type set
203- // to the result of passing the initial 512 bytes of written data to
204- // DetectContentType. Additionally, if the total size of all written
205- // data is under a few KB and there are no Flush calls, the
206- // Content-Length header is added automatically.
207- //
208- // Depending on the HTTP protocol version and the client, calling
209- // Write or WriteHeader may prevent future reads on the
210- // Request.Body. For HTTP/1.x requests, handlers should read any
211- // needed request body data before writing the response. Once the
212- // headers have been flushed (due to either an explicit Flusher.Flush
213- // call or writing enough data to trigger a flush), the request body
214- // may be unavailable. For HTTP/2 requests, the Go HTTP server permits
215- // handlers to continue to read the request body while concurrently
216- // writing the response. However, such behavior may not be supported
217- // by all HTTP/2 clients. Handlers should read before writing if
218- // possible to maximize compatibility.
219- func (ctx * Context ) Write (data []byte ) (int , error ) {
220- return ctx .Writer .Write (data )
221- }
222-
223- // WriteHeader sends an HTTP response header with the provided
224- // status code.
225- //
226- // If WriteHeader is not called explicitly, the first call to Write
227- // will trigger an implicit WriteHeader(http.StatusOK).
228- // Thus explicit calls to WriteHeader are mainly used to
229- // send error codes or 1xx informational responses.
100+ // NewUID get a new KSUID.
230101//
231- // The provided code must be a valid HTTP 1xx-5xx status code.
232- // Any number of 1xx headers may be written, followed by at most
233- // one 2xx-5xx header. 1xx headers are sent immediately, but 2xx-5xx
234- // headers may be buffered. Use the Flusher interface to send
235- // buffered data. The header map is cleared when 2xx-5xx headers are
236- // sent, but not with 1xx headers.
102+ // KSUID is for K-Sortable Unique IDentifier. It is a kind of globally unique identifier similar to a RFC 4122 UUID,
103+ // built from the ground-up to be "naturally" sorted by generation timestamp without any special type-aware logic.
237104//
238- // The server will automatically send a 100 (Continue) header
239- // on the first read from the request body if the request has
240- // an "Expect: 100-continue" header.
241- func (ctx * Context ) WriteHeader (statusCode int ) {
242- ctx .Writer .WriteHeader (statusCode )
243- }
244-
245- // SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
246- // The provided cookie must have a valid Name. Invalid cookies may be silently dropped.
247- func (ctx * Context ) SetCookie (cookie * http.Cookie ) {
248- http .SetCookie (ctx .Writer , cookie )
249- }
250-
251- // GetCookie returns the named cookie provided in the request or nil if not found.
252- // If multiple cookies match the given name, only one cookie will be returned.
253- func (ctx * Context ) GetCookie (name string ) * http.Cookie {
254- // @todo: ctx.Request.readCookies is slow
255- if cookie , err := ctx .Request .Cookie (name ); err == nil {
256- return cookie
257- }
258- return nil
105+ // See: https://github.com/segmentio/ksuid
106+ func (ctx * Context ) NewUID () (uid string ) {
107+ return NewUID ()
259108}
260109
261- // DeleteCookie delete a cookie by name
262- func (ctx * Context ) DeleteCookie (name string ) {
263- http .SetCookie (ctx .Writer , & http.Cookie {
264- Name : name ,
265- Value : "" ,
266- Path : "/" ,
267- HttpOnly : true ,
268- Expires : time .Now (),
269- MaxAge : - 1 ,
270- })
110+ // Router get current router reference
111+ func (ctx * Context ) Router () * Router {
112+ return ctx .router
271113}
272114
273115// BeforeSend Registers a callback to be invoked before the response is sent.
274116//
275117// Callbacks are invoked in the reverse order they are defined (callbacks defined first are invoked last).
276118func (ctx * Context ) BeforeSend (callback func ()) error {
277119 if spy , is := ctx .Writer .(* ResponseWriterSpy ); is {
278- return spy .beforeSend (callback )
120+ return spy .beforeWriteHeader (callback )
279121 }
280122 return nil
281123}
282124
283125func (ctx * Context ) AfterSend (callback func ()) error {
284126 if spy , is := ctx .Writer .(* ResponseWriterSpy ); is {
285- return spy .afterSend (callback )
127+ return spy .afterWrite (callback )
286128 }
287129 return nil
288130}
289131
290132func (ctx * Context ) write () {
291133 if spy , is := ctx .Writer .(* ResponseWriterSpy ); is {
292- if ! spy .wrote {
134+ if ! spy .writeStarted {
293135 ctx .WriteHeader (http .StatusOK )
294136 }
295137 }
296138}
297139
298- func NewUID () (uid string ) {
299- return ksuid .New ().String ()
300- }
301-
302- // NewUID get a new KSUID.
303- //
304- // KSUID is for K-Sortable Unique IDentifier. It is a kind of globally unique identifier similar to a RFC 4122 UUID,
305- // built from the ground-up to be "naturally" sorted by generation timestamp without any special type-aware logic.
306- //
307- // See: https://github.com/segmentio/ksuid
308- func (ctx * Context ) NewUID () (uid string ) {
309- return NewUID ()
140+ // addParameter adds a new parameter to the Context.
141+ func (ctx * Context ) addParameter (name string , value string ) {
142+ ctx .paramNames [ctx .paramCount ] = name
143+ ctx .paramValues [ctx .paramCount ] = value
144+ ctx .paramCount ++
310145}
311146
312147func (ctx * Context ) parsePathSegments () {
0 commit comments