已合并
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
已合并
Cangjie-panmengting创建于 7月25日
1 个文件变更+40-33
@@ -649,43 +649,50 @@ class ConnNode <: BodyProviderConn {
649 // send request body649 // send request body
650 let fut = spawn {sendRequestBodyTimeout(request, expectContinuation, shouldSendBody)}650 let fut = spawn {sendRequestBodyTimeout(request, expectContinuation, shouldSendBody)}
651 651 
652- // read response652+ 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 closed692 // 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 this694 // h1Engine.returnConn() does this
695+ let response = responseOp ?? throw HttpException("Internal error, response is None.")
689 response.connNode = this696 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") {