# frozen_string_literal: truebeginrequire'async'require'async/http'rescueLoadError# async-http not foundendifdefined?(Async::HTTP)moduleWebMockmoduleHttpLibAdaptersclassAsyncHttpClientAdapter<HttpLibAdapteradapter_for:async_http_clientOriginalAsyncHttpClient=Async::HTTP::Clientunlessconst_defined?(:OriginalAsyncHttpClient)class<<selfdefenable!Async::HTTP.send(:remove_const,:Client)Async::HTTP.send(:const_set,:Client,Async::HTTP::WebMockClientWrapper)enddefdisable!Async::HTTP.send(:remove_const,:Client)Async::HTTP.send(:const_set,:Client,OriginalAsyncHttpClient)endendendendendmoduleAsyncmoduleHTTPclassWebMockClientWrapper<Clientdefinitialize(endpoint,protocol: endpoint.protocol,scheme: endpoint.scheme,authority: endpoint.authority,**options)webmock_endpoint=WebMockEndpoint.new(scheme,authority,protocol)@network_client=WebMockClient.new(endpoint,**options)@webmock_client=WebMockClient.new(webmock_endpoint,**options)@endpoint=endpoint@scheme=scheme@authority=authorityenddefcall(request)request.scheme||=self.schemerequest.authority||=self.authorityrequest_signature=build_request_signature(request)WebMock::RequestRegistry.instance.requested_signatures.put(request_signature)webmock_response=WebMock::StubRegistry.instance.response_for_request(request_signature)net_connect_allowed=WebMock.net_connect_allowed?(request_signature.uri)real_request=falseifwebmock_responsewebmock_response.raise_error_if_anyraiseAsync::TimeoutError,'WebMock timeout error'ifwebmock_response.should_timeoutWebMockApplication.add_webmock_response(request,webmock_response)response=@webmock_client.call(request)elsifnet_connect_allowedresponse=@network_client.call(request)real_request=trueelseraiseWebMock::NetConnectNotAllowedError.new(request_signature)unlesswebmock_responseendifWebMock::CallbackRegistry.any_callbacks?webmock_response||=build_webmock_response(response)WebMock::CallbackRegistry.invoke_callbacks({lib: :async_http_client,real_request: real_request},request_signature,webmock_response)endresponseenddefclose@network_client.close@webmock_client.closeendprivatedefbuild_request_signature(request)body=request.readrequest.body=::Protocol::HTTP::Body::Buffered.wrap(body)WebMock::RequestSignature.new(request.method.downcase.to_sym,"#{request.scheme}://#{request.authority}#{request.path}",headers: request.headers.to_h,body: body)enddefbuild_webmock_response(response)body=response.readresponse.body=::Protocol::HTTP::Body::Buffered.wrap(body)webmock_response=WebMock::Response.newwebmock_response.status=[response.status,::Protocol::HTTP1::Reason::DESCRIPTIONS[response.status]]webmock_response.headers=build_webmock_response_headers(response)webmock_response.body=bodywebmock_responseenddefbuild_webmock_response_headers(response)response.headers.each.each_with_object({})do|(k,v),o|o[k]||=[]o[k]<<vendendendclassWebMockClient<ClientendclassWebMockEndpointdefinitialize(scheme,authority,protocol)@scheme=scheme@authority=authority@protocol=protocolendattr:scheme,:authority,:protocoldefconnectserver_socket,client_socket=create_connected_socketsAsync(transient: true)doaccept_socket(server_socket)endclient_socketenddefinspect"\#<#{self.class}> #{scheme}://#{authority} protocol=#{protocol}"endprivatedefsocket_classdefined?(Async::IO::Socket)?Async::IO::Socket:Socketenddefcreate_connected_socketspair=beginsocket_class.pair(Socket::AF_UNIX,Socket::SOCK_STREAM)rescueErrno::EAFNOSUPPORTsocket_class.pair(Socket::AF_INET,Socket::SOCK_STREAM)endpair.tapdo|sockets|sockets.eachdo|socket|socket.instance_variable_set:@alpn_protocol,nilsocket.instance_evaldodefalpn_protocolnil# means HTTP11 will be used for HTTPSendendendendenddefaccept_socket(socket)server=Async::HTTP::Server.new(WebMockApplication,self)server.accept(socket,socket.remote_address)endendmoduleWebMockApplicationWEBMOCK_REQUEST_ID_HEADER='x-webmock-request-id'.freezeclass<<selfdefcall(request)request.readwebmock_response=get_webmock_response(request)build_response(webmock_response)enddefadd_webmock_response(request,webmock_response)webmock_request_id=request.object_id.to_srequest.headers.add(WEBMOCK_REQUEST_ID_HEADER,webmock_request_id)webmock_responses[webmock_request_id]=webmock_responseenddefget_webmock_response(request)webmock_request_id=request.headers[WEBMOCK_REQUEST_ID_HEADER][0]webmock_responses.fetch(webmock_request_id)endprivatedefwebmock_responses@webmock_responses||={}enddefbuild_response(webmock_response)headers=(webmock_response.headers||{}).each_with_object([])do|(k,value),o|Array(value).eachdo|v|o.push[k,v]endend::Protocol::HTTP::Response[webmock_response.status[0],headers,webmock_response.body]endendendendendend