mirror of
https://github.com/diamondburned/arikawa.git
synced 2025-01-21 12:07:14 +00:00
httputil: Fixed unlock of unlocked mutex bug
This commit is contained in:
parent
2a032ebfab
commit
94cca0adca
|
@ -128,14 +128,15 @@ func (l *Limiter) Acquire(ctx context.Context, path string) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Release releases the URL from the locks. This doesn't need a context for
|
// Release releases the URL from the locks. This doesn't need a context for
|
||||||
// timing out, it doesn't block that much.
|
// timing out, since it doesn't block that much.
|
||||||
func (l *Limiter) Release(path string, headers http.Header) error {
|
func (l *Limiter) Release(path string, headers http.Header) error {
|
||||||
b := l.getBucket(path, false)
|
b := l.getBucket(path, false)
|
||||||
if b == nil {
|
if b == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
defer b.lock.Unlock()
|
// TryUnlock because Release may be called when Acquire has not been.
|
||||||
|
defer b.lock.TryUnlock()
|
||||||
|
|
||||||
// Check custom limiter
|
// Check custom limiter
|
||||||
if b.custom != nil {
|
if b.custom != nil {
|
||||||
|
|
|
@ -42,6 +42,16 @@ func (m *CtxMutex) Lock(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TryUnlock returns true if the mutex has been unlocked.
|
||||||
|
func (m *CtxMutex) TryUnlock() bool {
|
||||||
|
select {
|
||||||
|
case <-m.mut:
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m *CtxMutex) Unlock() {
|
func (m *CtxMutex) Unlock() {
|
||||||
select {
|
select {
|
||||||
case <-m.mut:
|
case <-m.mut:
|
||||||
|
|
|
@ -67,19 +67,22 @@ func (c *Client) Context() context.Context {
|
||||||
return c.context
|
return c.context
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) applyOptions(r httpdriver.Request, extra []RequestOption) error {
|
// applyOptions tries to apply all options. It does not halt if a single option
|
||||||
|
// fails, and the error returned is the latest error.
|
||||||
|
func (c *Client) applyOptions(r httpdriver.Request, extra []RequestOption) (e error) {
|
||||||
for _, opt := range c.OnRequest {
|
for _, opt := range c.OnRequest {
|
||||||
if err := opt(r); err != nil {
|
if err := opt(r); err != nil {
|
||||||
return err
|
e = err
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, opt := range extra {
|
|
||||||
if err := opt(r); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
for _, opt := range extra {
|
||||||
|
if err := opt(r); err != nil {
|
||||||
|
e = err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) MeanwhileMultipart(
|
func (c *Client) MeanwhileMultipart(
|
||||||
|
@ -158,6 +161,8 @@ func (c *Client) Request(method, url string, opts ...RequestOption) (httpdriver.
|
||||||
var r httpdriver.Response
|
var r httpdriver.Response
|
||||||
var status int
|
var status int
|
||||||
|
|
||||||
|
// The c.Retries < 1 check ensures that we retry forever if that field is
|
||||||
|
// less than 1.
|
||||||
for i := uint(0); c.Retries < 1 || i < c.Retries; i++ {
|
for i := uint(0); c.Retries < 1 || i < c.Retries; i++ {
|
||||||
q, err := c.Client.NewRequest(c.context, method, url)
|
q, err := c.Client.NewRequest(c.context, method, url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -165,18 +170,33 @@ func (c *Client) Request(method, url string, opts ...RequestOption) (httpdriver.
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := c.applyOptions(q, opts); err != nil {
|
if err := c.applyOptions(q, opts); err != nil {
|
||||||
|
// We failed to apply an option, so we should call all OnResponse
|
||||||
|
// handler to clean everything up.
|
||||||
|
for _, fn := range c.OnResponse {
|
||||||
|
fn(q, nil)
|
||||||
|
}
|
||||||
|
// Exit after cleaning everything up.
|
||||||
return nil, errors.Wrap(err, "failed to apply options")
|
return nil, errors.Wrap(err, "failed to apply options")
|
||||||
}
|
}
|
||||||
|
|
||||||
r, doErr = c.Client.Do(q)
|
r, doErr = c.Client.Do(q)
|
||||||
|
|
||||||
|
// Error that represents the latest error in the chain.
|
||||||
|
var onRespErr error
|
||||||
|
|
||||||
// Call OnResponse() even if the request failed.
|
// Call OnResponse() even if the request failed.
|
||||||
for _, fn := range c.OnResponse {
|
for _, fn := range c.OnResponse {
|
||||||
|
// Be sure to call ALL OnResponse handlers.
|
||||||
if err := fn(q, r); err != nil {
|
if err := fn(q, r); err != nil {
|
||||||
return nil, err
|
onRespErr = err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if onRespErr != nil {
|
||||||
|
return nil, errors.Wrap(err, "OnResponse handler failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry if the request failed.
|
||||||
if doErr != nil {
|
if doErr != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue