(timeout time.Duration)
| 533 | } |
| 534 | |
| 535 | func timeoutMiddleware(timeout time.Duration) func(http.Handler) http.Handler { |
| 536 | return func(next http.Handler) http.Handler { |
| 537 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 538 | ctx, cancel := context.WithTimeout(r.Context(), timeout) |
| 539 | defer cancel() |
| 540 | |
| 541 | timeoutWriter := &timeoutResponseWriter{ |
| 542 | header: make(http.Header), |
| 543 | } |
| 544 | |
| 545 | panicChan := make(chan any, 1) |
| 546 | serverDone := make(chan struct{}) |
| 547 | go func() { |
| 548 | defer func() { |
| 549 | if p := recover(); p != nil { |
| 550 | panicChan <- p |
| 551 | } |
| 552 | }() |
| 553 | |
| 554 | next.ServeHTTP(timeoutWriter, r.WithContext(ctx)) |
| 555 | close(serverDone) |
| 556 | }() |
| 557 | |
| 558 | select { |
| 559 | case p := <-panicChan: |
| 560 | panic(p) |
| 561 | |
| 562 | case <-serverDone: |
| 563 | timeoutWriter.finallyWrite(w) |
| 564 | |
| 565 | case <-ctx.Done(): |
| 566 | err := ctx.Err() |
| 567 | |
| 568 | if err == context.DeadlineExceeded { |
| 569 | httpError := &HTTPError{ |
| 570 | HTTPStatus: http.StatusGatewayTimeout, |
| 571 | ErrorCode: apierrors.ErrorCodeRequestTimeout, |
| 572 | Message: "Processing this request timed out, please retry after a moment.", |
| 573 | } |
| 574 | |
| 575 | httpError = httpError.WithInternalError(err) |
| 576 | |
| 577 | HandleResponseError(httpError, w, r) |
| 578 | } else { |
| 579 | // unrecognized context error, so we should wait for the server to finish |
| 580 | // and write out the response |
| 581 | <-serverDone |
| 582 | |
| 583 | timeoutWriter.finallyWrite(w) |
| 584 | } |
| 585 | } |
| 586 | }) |
| 587 | } |
| 588 | } |
searching dependent graphs…