已合并
fix(http): prevent concurrent access to HttpBufferedBody in http1.1 client #728
Cangjie-panmengting创建于 7月25日
fix(http): prevent concurrent access to HttpBufferedBody in http1.1 client #728
已合并
共 1 个文件变更+40-33
| @@ -649,43 +649,50 @@ class ConnNode <: BodyProviderConn { | |||
| 649 | // send request body | 649 | // send request body |
| 650 | let fut = spawn {sendRequestBodyTimeout(request, expectContinuation, shouldSendBody)} | 650 | let fut = spawn {sendRequestBodyTimeout(request, expectContinuation, shouldSendBody)} |
| 651 | 651 | ||
| 652 | - // read response | 652 | + var responseOp: ?HttpResponse = None |
| 653 | - | ||
| 654 | - // method is used to decide whether there is a response body | ||
| 655 | - // the 1xx response will be discarded | ||
| 656 | - setReadTimer(request.readTimeout ?? readTimeout) | ||
| 657 | - var response = readResponse(request) | ||
| 658 | - if (logger.enabled(LogLevel.DEBUG)) { | ||
| 659 | - httpLogDebug(logger, "[ConnNode#sendRequestTimeout] Client1.1 read response ${response}") | ||
| 660 | - } | ||
| 661 | - // process 1xx response | ||
| 662 | - response = process1xxResponse(response, request, expectContinuation, shouldSendBody) | ||
| 663 | - shouldSendBody.swap(false) | ||
| 664 | - if (expectContinuation.load()) { | ||
| 665 | - synchronized(continueMonitor) { | ||
| 666 | - continueMonitor.notifyAll() | ||
| 667 | - } | ||
| 668 | - } | ||
| 669 | - | ||
| 670 | - // client will close the conn after reading the response message containing the "close" connection option | ||
| 671 | - // upgrade and connect only depend on the status code | ||
| 672 | - if (this.shouldClose.load() && !isUpgraded && request.method != "CONNECT") { | ||
| 673 | - match (response.body) { | ||
| 674 | - case body: HttpNormalBodyProvider => | ||
| 675 | - response._body = HttpNormalBody(body) | ||
| 676 | - h1Engine.closeConnInUse(this) | ||
| 677 | - case _: HttpEmptyBody => h1Engine.closeConnInUse(this) | ||
| 678 | - case _ => () | ||
| 679 | - } | ||
| 680 | - } | ||
| 681 | - // wait until the sending is complete. | ||
| 682 | - // when the sending fails, the sending coroutine generates a log | ||
| 683 | try { | 653 | try { |
| 684 | - fut.get() | 654 | + // read response |
| 685 | - } catch (e: SocketException) {} | 655 | + |
| 656 | + // method is used to decide whether there is a response body | ||
| 657 | + // the 1xx response will be discarded | ||
| 658 | + setReadTimer(request.readTimeout ?? readTimeout) | ||
| 659 | + var response = readResponse(request) | ||
| 660 | + responseOp = response | ||
| 661 | + if (logger.enabled(LogLevel.DEBUG)) { | ||
| 662 | + httpLogDebug(logger, "[ConnNode#sendRequestTimeout] Client1.1 read response ${response}") | ||
| 663 | + } | ||
| 664 | + // process 1xx response | ||
| 665 | + response = process1xxResponse(response, request, expectContinuation, shouldSendBody) | ||
| 666 | + responseOp = response | ||
| 667 | + shouldSendBody.swap(false) | ||
| 668 | + if (expectContinuation.load()) { | ||
| 669 | + synchronized(continueMonitor) { | ||
| 670 | + continueMonitor.notifyAll() | ||
| 671 | + } | ||
| 672 | + } | ||
| 673 | + | ||
| 674 | + // client will close the conn after reading the response message containing the "close" connection option | ||
| 675 | + // upgrade and connect only depend on the status code | ||
| 676 | + if (this.shouldClose.load() && !isUpgraded && request.method != "CONNECT") { | ||
| 677 | + match (response.body) { | ||
| 678 | + case body: HttpNormalBodyProvider => | ||
| 679 | + response._body = HttpNormalBody(body) | ||
| 680 | + h1Engine.closeConnInUse(this) | ||
| 681 | + case _: HttpEmptyBody => h1Engine.closeConnInUse(this) | ||
| 682 | + case _ => () | ||
| 683 | + } | ||
| 684 | + } | ||
| 685 | + } finally { | ||
| 686 | + // wait until the sending is complete. | ||
| 687 | + // when the sending fails, the sending coroutine generates a log | ||
| 688 | + try { | ||
| 689 | + fut.get() | ||
| 690 | + } catch (_: SocketException) {} | ||
| 691 | + } | ||
| 686 | // the connNode will be returned or closed | 692 | // the connNode will be returned or closed |
| 687 | // until the caller has finished consuming the body. | 693 | // until the caller has finished consuming the body. |
| 688 | // h1Engine.returnConn() does this | 694 | // h1Engine.returnConn() does this |
| 695 | + let response = responseOp ?? throw HttpException("Internal error, response is None.") | ||
| 689 | response.connNode = this | 696 | response.connNode = this |
| 690 | if (response.body is HttpEmptyBody) { | 697 | if (response.body is HttpEmptyBody) { |
| 691 | if (isUpgraded || request.method == "CONNECT") { | 698 | if (isUpgraded || request.method == "CONNECT") { |