blob: 565fcd655f60aa284a580e9d96a4ebc1bc8f96c5 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.servicecomb.serviceregistry.client.http;
import java.io.ByteArrayInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.servicecomb.foundation.auth.AuthHeaderProvider;
import org.apache.servicecomb.foundation.auth.SignRequest;
import org.apache.servicecomb.foundation.common.net.IpPort;
import org.apache.servicecomb.foundation.vertx.client.http.HttpClientWithContext;
import org.apache.servicecomb.serviceregistry.config.ServiceRegistryConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import io.vertx.core.Future;
import io.vertx.core.Handler;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.http.HttpMethod;
final class RestClientUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(RestClientUtil.class);
static final String HEADER_CONTENT_TYPE = "Content-Type";
static final String HEADER_USER_AGENT = "User-Agent";
static final String HEADER_TENANT_NAME = "x-domain-name";
private final List<AuthHeaderProvider> authHeaderProviders;
private final int requestTimeout;
private final String tenantName;
private final HttpClientPool httpClientPool;
RestClientUtil(ServiceRegistryConfig serviceRegistryConfig) {
this.authHeaderProviders = serviceRegistryConfig.getAuthHeaderProviders();
this.requestTimeout = serviceRegistryConfig.getRequestTimeout();
this.tenantName = serviceRegistryConfig.getTenantName();
this.httpClientPool = new HttpClientPool(serviceRegistryConfig.getClientName());
}
public void httpDo(RequestContext requestContext, Handler<RestResponse> responseHandler) {
if (requestContext.getParams().getTimeout() != 0) {
httpDo(requestContext.getParams().getTimeout(), requestContext, responseHandler);
return;
}
httpDo(requestTimeout, requestContext, responseHandler);
}
public void httpDo(long timeout, RequestContext requestContext, Handler<RestResponse> responseHandler) {
HttpClientWithContext vertxHttpClient = httpClientPool.getClient();
vertxHttpClient.runOnContext(httpClient -> {
IpPort ipPort = requestContext.getIpPort();
HttpMethod httpMethod = requestContext.getMethod();
RequestParam requestParam = requestContext.getParams();
if (ipPort == null) {
LOGGER.error("request address is null");
responseHandler.handle(new RestResponse(requestContext, null));
return;
}
// query params
StringBuilder url = new StringBuilder(requestContext.getUri());
String queryParams = requestParam.getQueryParams();
if (!queryParams.isEmpty()) {
url.append(url.lastIndexOf("?") > 0 ? "&" : "?")
.append(queryParams);
}
httpClient
.request(httpMethod, ipPort.getPort(), ipPort.getHostOrIp(), url.toString()).compose(httpClientRequest -> {
httpClientRequest.setTimeout(timeout);
//headers
Map<String, String> headers = defaultHeaders();
httpClientRequest.headers().addAll(headers);
if (requestParam.getHeaders() != null && requestParam.getHeaders().size() > 0) {
headers.putAll(requestParam.getHeaders());
for (Map.Entry<String, String> header : requestParam.getHeaders().entrySet()) {
httpClientRequest.putHeader(header.getKey(), header.getValue());
}
}
// cookies header
if (requestParam.getCookies() != null && requestParam.getCookies().size() > 0) {
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String> cookie : requestParam.getCookies().entrySet()) {
stringBuilder.append(cookie.getKey())
.append("=")
.append(cookie.getValue())
.append("; ");
}
httpClientRequest.putHeader("Cookie", stringBuilder.toString());
headers.put("Cookie", stringBuilder.toString());
}
//SignAuth
SignRequest signReq = createSignRequest(requestContext.getMethod().toString(),
requestContext.getIpPort(),
requestContext.getParams(),
url.toString(),
headers);
httpClientRequest.headers().addAll(getSignAuthHeaders(signReq));
// body
if (httpMethod != HttpMethod.GET && requestParam.getBody() != null && requestParam.getBody().length > 0) {
return httpClientRequest.send(Buffer.buffer(requestParam.getBody()))
.compose(response -> {
responseHandler.handle(new RestResponse(requestContext, response));
return Future.succeededFuture();
});
} else {
return httpClientRequest.send()
.compose(response -> {
responseHandler.handle(new RestResponse(requestContext, response));
return Future.succeededFuture();
});
}
}).onFailure(failure -> {
LOGGER.error("{} {} fail, endpoint is {}:{}, message: {}",
httpMethod,
url,
ipPort.getHostOrIp(),
ipPort.getPort(),
failure.getMessage());
if (failure instanceof UnknownHostException) {
// help analyses DNS problem
LOGGER.error("DNS resolve failed!", failure);
}
responseHandler.handle(new RestResponse(requestContext, null));
});
});
}
public RequestContext createRequestContext(HttpMethod method, IpPort ipPort, String uri,
RequestParam requestParam) {
RequestContext requestContext = new RequestContext();
requestContext.setMethod(method);
requestContext.setIpPort(ipPort);
requestContext.setUri(uri);
requestContext.setParams(requestParam);
return requestContext;
}
public SignRequest createSignRequest(String method, IpPort ipPort, RequestParam requestParam, String url,
Map<String, String> headers) {
SignRequest signReq = new SignRequest();
StringBuilder endpoint = new StringBuilder("https://" + ipPort.getHostOrIp());
endpoint.append(":").append(ipPort.getPort());
endpoint.append(url);
try {
signReq.setEndpoint(new URI(endpoint.toString()));
} catch (URISyntaxException e) {
LOGGER.error("set uri failed, uri is {}, message: {}", endpoint, e.getMessage());
}
signReq.setContent((requestParam.getBody() != null && requestParam.getBody().length > 0)
? new ByteArrayInputStream(requestParam.getBody())
: null);
signReq.setHeaders(headers);
signReq.setHttpMethod(method);
signReq.setQueryParams(requestParam.getQueryParamsMap());
return signReq;
}
private Map<String, String> defaultHeaders() {
Map<String, String> headers = new HashMap<>();
headers.put(HEADER_CONTENT_TYPE, "application/json");
headers.put(HEADER_USER_AGENT, "cse-serviceregistry-client/1.0.0");
headers.put(HEADER_TENANT_NAME, tenantName);
return headers;
}
public void get(IpPort ipPort, String uri, RequestParam requestParam,
Handler<RestResponse> responseHandler) {
httpDo(createRequestContext(HttpMethod.GET, ipPort, uri, requestParam), responseHandler);
}
public void post(IpPort ipPort, String uri, RequestParam requestParam,
Handler<RestResponse> responseHandler) {
httpDo(createRequestContext(HttpMethod.POST, ipPort, uri, requestParam), responseHandler);
}
public void put(IpPort ipPort, String uri, RequestParam requestParam,
Handler<RestResponse> responseHandler) {
httpDo(createRequestContext(HttpMethod.PUT, ipPort, uri, requestParam), responseHandler);
}
public void delete(IpPort ipPort, String uri, RequestParam requestParam,
Handler<RestResponse> responseHandler) {
httpDo(createRequestContext(HttpMethod.DELETE, ipPort, uri, requestParam), responseHandler);
}
public Map<String, String> getSignAuthHeaders(SignRequest signReq) {
Map<String, String> headers = new HashMap<>();
authHeaderProviders.forEach(provider -> headers.putAll(provider.getSignAuthHeaders(signReq)));
return headers;
}
}