Java tutorial
/** * 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.hadoop.gateway.dispatch; import org.apache.hadoop.gateway.SpiGatewayMessages; import org.apache.hadoop.gateway.SpiGatewayResources; import org.apache.hadoop.gateway.audit.api.Action; import org.apache.hadoop.gateway.audit.api.ActionOutcome; import org.apache.hadoop.gateway.audit.api.AuditServiceFactory; import org.apache.hadoop.gateway.audit.api.Auditor; import org.apache.hadoop.gateway.audit.api.ResourceType; import org.apache.hadoop.gateway.audit.log4j.audit.AuditConstants; import org.apache.hadoop.gateway.config.Configure; import org.apache.hadoop.gateway.config.Default; import org.apache.hadoop.gateway.config.GatewayConfig; import org.apache.hadoop.gateway.i18n.messages.MessagesFactory; import org.apache.hadoop.gateway.i18n.resources.ResourcesFactory; import org.apache.hadoop.gateway.util.MimeTypes; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.ContentType; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.HashSet; import java.util.Set; /** * */ public class DefaultDispatch extends AbstractGatewayDispatch { protected static final String SET_COOKIE = "SET-COOKIE"; protected static final String WWW_AUTHENTICATE = "WWW-AUTHENTICATE"; protected static SpiGatewayMessages LOG = MessagesFactory.get(SpiGatewayMessages.class); protected static SpiGatewayResources RES = ResourcesFactory.get(SpiGatewayResources.class); protected static Auditor auditor = AuditServiceFactory.getAuditService().getAuditor( AuditConstants.DEFAULT_AUDITOR_NAME, AuditConstants.KNOX_SERVICE_NAME, AuditConstants.KNOX_COMPONENT_NAME); private Set<String> outboundResponseExcludeHeaders; //Buffer size in bytes private int replayBufferSize = -1; @Override public void init() { super.init(); outboundResponseExcludeHeaders = new HashSet<>(); outboundResponseExcludeHeaders.add(SET_COOKIE); outboundResponseExcludeHeaders.add(WWW_AUTHENTICATE); } @Override public void destroy() { } protected int getReplayBufferSize() { if (replayBufferSize > 0) { return Math.abs(replayBufferSize / 1024); } return replayBufferSize; } @Configure protected void setReplayBufferSize(@Default("-1") int size) { setReplayBufferSizeInBytes(size); } protected int getReplayBufferSizeInBytes() { return replayBufferSize; } protected void setReplayBufferSizeInBytes(int size) { if (size > 0) { size *= 1024; } replayBufferSize = size; } protected void executeRequest(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse) throws IOException { HttpResponse inboundResponse = executeOutboundRequest(outboundRequest); writeOutboundResponse(outboundRequest, inboundRequest, outboundResponse, inboundResponse); } protected HttpResponse executeOutboundRequest(HttpUriRequest outboundRequest) throws IOException { LOG.dispatchRequest(outboundRequest.getMethod(), outboundRequest.getURI()); HttpResponse inboundResponse; try { auditor.audit(Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.UNAVAILABLE, RES.requestMethod(outboundRequest.getMethod())); if (!"true".equals(System.getProperty(GatewayConfig.HADOOP_KERBEROS_SECURED))) { // Hadoop cluster not Kerberos enabled addCredentialsToRequest(outboundRequest); } inboundResponse = client.execute(outboundRequest); int statusCode = inboundResponse.getStatusLine().getStatusCode(); if (statusCode != 201) { LOG.dispatchResponseStatusCode(statusCode); } else { Header location = inboundResponse.getFirstHeader("Location"); if (location == null) { LOG.dispatchResponseStatusCode(statusCode); } else { LOG.dispatchResponseCreatedStatusCode(statusCode, location.getValue()); } } auditor.audit(Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.SUCCESS, RES.responseStatus(statusCode)); } catch (Exception e) { // We do not want to expose back end host. port end points to clients, see JIRA KNOX-58 auditor.audit(Action.DISPATCH, outboundRequest.getURI().toString(), ResourceType.URI, ActionOutcome.FAILURE); LOG.dispatchServiceConnectionException(outboundRequest.getURI(), e); throw new IOException(RES.dispatchConnectionError()); } return inboundResponse; } protected void writeOutboundResponse(HttpUriRequest outboundRequest, HttpServletRequest inboundRequest, HttpServletResponse outboundResponse, HttpResponse inboundResponse) throws IOException { // Copy the client respond header to the server respond. outboundResponse.setStatus(inboundResponse.getStatusLine().getStatusCode()); Header[] headers = inboundResponse.getAllHeaders(); Set<String> excludeHeaders = getOutboundResponseExcludeHeaders(); boolean hasExcludeHeaders = false; if ((excludeHeaders != null) && !(excludeHeaders.isEmpty())) { hasExcludeHeaders = true; } for (Header header : headers) { String name = header.getName(); if (hasExcludeHeaders && excludeHeaders.contains(name.toUpperCase())) { continue; } String value = header.getValue(); outboundResponse.addHeader(name, value); } HttpEntity entity = inboundResponse.getEntity(); if (entity != null) { outboundResponse.setContentType(getInboundResponseContentType(entity)); //KM[ If this is set here it ends up setting the content length to the content returned from the server. // This length might not match if the the content is rewritten. // long contentLength = entity.getContentLength(); // if( contentLength <= Integer.MAX_VALUE ) { // outboundResponse.setContentLength( (int)contentLength ); // } //] InputStream stream = entity.getContent(); try { writeResponse(inboundRequest, outboundResponse, stream); } finally { closeInboundResponse(inboundResponse, stream); } } } private String getInboundResponseContentType(final HttpEntity entity) { String fullContentType = null; if (entity != null) { ContentType entityContentType = ContentType.get(entity); if (entityContentType != null) { if (entityContentType.getCharset() == null) { final String entityMimeType = entityContentType.getMimeType(); final String defaultCharset = MimeTypes.getDefaultCharsetForMimeType(entityMimeType); if (defaultCharset != null) { LOG.usingDefaultCharsetForEntity(entityMimeType, defaultCharset); entityContentType = entityContentType.withCharset(defaultCharset); } } else { LOG.usingExplicitCharsetForEntity(entityContentType.getMimeType(), entityContentType.getCharset()); } fullContentType = entityContentType.toString(); } } if (fullContentType == null) { LOG.unknownResponseEntityContentType(); } else { LOG.inboundResponseEntityContentType(fullContentType); } return fullContentType; } protected void closeInboundResponse(HttpResponse response, InputStream stream) throws IOException { try { stream.close(); } finally { if (response instanceof Closeable) { ((Closeable) response).close(); } } } /** * This method provides a hook for specialized credential propagation * in subclasses. * * @param outboundRequest */ protected void addCredentialsToRequest(HttpUriRequest outboundRequest) { } protected HttpEntity createRequestEntity(HttpServletRequest request) throws IOException { String contentType = request.getContentType(); int contentLength = request.getContentLength(); InputStream contentStream = request.getInputStream(); HttpEntity entity; if (contentType == null) { entity = new InputStreamEntity(contentStream, contentLength); } else { entity = new InputStreamEntity(contentStream, contentLength, ContentType.parse(contentType)); } GatewayConfig config = (GatewayConfig) request.getServletContext() .getAttribute(GatewayConfig.GATEWAY_CONFIG_ATTRIBUTE); if (config != null && config.isHadoopKerberosSecured()) { //Check if delegation token is supplied in the request boolean delegationTokenPresent = false; String queryString = request.getQueryString(); if (queryString != null) { delegationTokenPresent = queryString.startsWith("delegation=") || queryString.contains("&delegation="); } if (replayBufferSize < 0) { replayBufferSize = config.getHttpServerRequestBuffer(); } if (!delegationTokenPresent && replayBufferSize > 0) { entity = new PartiallyRepeatableHttpEntity(entity, replayBufferSize); } } return entity; } @Override public void doGet(URI url, HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException { HttpGet method = new HttpGet(url); // https://issues.apache.org/jira/browse/KNOX-107 - Service URLs not rewritten for WebHDFS GET redirects // This is now taken care of in DefaultHttpClientFactory.createHttpClient // and setting params here causes configuration setup there to be ignored there. // method.getParams().setBooleanParameter("http.protocol.handle-redirects", false); copyRequestHeaderFields(method, request); executeRequest(method, request, response); } @Override public void doOptions(URI url, HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException { HttpOptions method = new HttpOptions(url); executeRequest(method, request, response); } @Override public void doPut(URI url, HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException { HttpPut method = new HttpPut(url); HttpEntity entity = createRequestEntity(request); method.setEntity(entity); copyRequestHeaderFields(method, request); executeRequest(method, request, response); } @Override public void doPost(URI url, HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException { HttpPost method = new HttpPost(url); HttpEntity entity = createRequestEntity(request); method.setEntity(entity); copyRequestHeaderFields(method, request); executeRequest(method, request, response); } @Override public void doDelete(URI url, HttpServletRequest request, HttpServletResponse response) throws IOException, URISyntaxException { HttpDelete method = new HttpDelete(url); copyRequestHeaderFields(method, request); executeRequest(method, request, response); } public Set<String> getOutboundResponseExcludeHeaders() { return outboundResponseExcludeHeaders; } }