Guest User

ProxyController

a guest
Feb 21st, 2019
680
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package foo.bar;
  2.  
  3. import foo.bar.RestTemplateFactory;
  4. import org.apache.commons.io.IOUtils;
  5. import org.slf4j.Logger;
  6. import org.slf4j.LoggerFactory;
  7. import org.springframework.beans.factory.annotation.Autowired;
  8. import org.springframework.core.io.InputStreamResource;
  9. import org.springframework.http.*;
  10. import org.springframework.util.LinkedMultiValueMap;
  11. import org.springframework.util.MultiValueMap;
  12. import org.springframework.web.bind.annotation.RequestBody;
  13. import org.springframework.web.bind.annotation.RequestMapping;
  14. import org.springframework.web.bind.annotation.ResponseBody;
  15. import org.springframework.web.bind.annotation.RestController;
  16. import org.springframework.web.client.HttpStatusCodeException;
  17. import org.springframework.web.client.RestTemplate;
  18. import org.springframework.web.multipart.MultipartFile;
  19. import org.springframework.web.multipart.MultipartHttpServletRequest;
  20. import org.springframework.web.util.UriComponentsBuilder;
  21.  
  22. import javax.servlet.http.HttpServletRequest;
  23. import javax.servlet.http.HttpServletResponse;
  24. import java.io.ByteArrayInputStream;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.net.URI;
  28. import java.net.URL;
  29. import java.util.ArrayList;
  30. import java.util.Collections;
  31. import java.util.Enumeration;
  32. import java.util.Iterator;
  33.  
  34. @RestController
  35. @RequestMapping("proxy")
  36. public class ProxyController {
  37.  
  38.     private Logger log = LoggerFactory.getLogger(ProxyController.class);
  39.     private final RestTemplateFactory restTemplateContextFactory;
  40.     private final TargetUrlBuilder targetUrlBuilder;
  41.  
  42.     @Autowired
  43.     public ProxyController(RestTemplateFactory restTemplateContextFactory, TargetUrlBuilder targetUrlBuilder) {
  44.         this.restTemplateContextFactory = restTemplateContextFactory;
  45.         this.targetUrlBuilder = targetUrlBuilder;
  46.     }
  47.  
  48.     @RequestMapping("/**")
  49.     @ResponseBody
  50.     public void proxy(@RequestBody(required = false) byte[] body,
  51.                       HttpMethod method,
  52.                       HttpServletRequest servletRequest,
  53.                       HttpServletResponse servletResponse) throws IOException {
  54.  
  55.         URL targetUrl = buildTargetUrl(servletRequest);
  56.         URI uri = buildUri(servletRequest, targetUrl);
  57.         HttpHeaders headers = copyHeaders(servletRequest);
  58.         HttpEntity httpEntity = buildHttpEntity(body, servletRequest, headers);
  59.  
  60.         sendProxyRequest(method, servletResponse, targetUrl, uri, httpEntity);
  61.     }
  62.  
  63.     private HttpEntity buildHttpEntity(@RequestBody(required = false) byte[] body, HttpServletRequest servletRequest, HttpHeaders headers) throws IOException {
  64.         HttpEntity httpEntity;
  65.  
  66.         if(servletRequest instanceof MultipartHttpServletRequest) {
  67.             httpEntity = buildHttpEntityFromMultipartRequest(servletRequest, headers);
  68.         } else {
  69.             httpEntity = new HttpEntity<>(body, headers);
  70.         }
  71.  
  72.         return httpEntity;
  73.     }
  74.  
  75.     private URL buildTargetUrl(HttpServletRequest servletRequest) {
  76.         URL targetUrl = getTargetUrl(servletRequest);
  77.         if(targetUrl == null) {
  78.             throw new RuntimeException("Failed to build target url.");
  79.         }
  80.         return targetUrl;
  81.     }
  82.  
  83.     private URI buildUri(HttpServletRequest servletRequest, URL targetUrl) {
  84.         return UriComponentsBuilder
  85.                     .fromUriString(targetUrl.toString())
  86.                     .query(servletRequest.getQueryString())
  87.                     .build(true).toUri();
  88.     }
  89.  
  90.     private HttpHeaders copyHeaders(HttpServletRequest servletRequest) {
  91.         HttpHeaders headers = new HttpHeaders();
  92.         Enumeration<String> headerNames = servletRequest.getHeaderNames();
  93.         while (headerNames.hasMoreElements()) {
  94.             String headerName = headerNames.nextElement();
  95.             headers.set(headerName, servletRequest.getHeader(headerName));
  96.         }
  97.         return headers;
  98.     }
  99.  
  100.     private HttpEntity<MultiValueMap<String, Object>> buildHttpEntityFromMultipartRequest(HttpServletRequest servletRequest, HttpHeaders headers) throws IOException {
  101.         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) servletRequest;
  102.         Iterator<String> itr = multipartRequest.getFileNames();
  103.         String fileName = itr.next();
  104.         MultipartFile file = multipartRequest.getFile(fileName);
  105.  
  106.         MultiValueMap<String, Object> parts = new LinkedMultiValueMap<>();
  107.         parts.add(fileName, new MultipartInputStreamFileResource(new ByteArrayInputStream(file.getBytes()), file.getOriginalFilename()));
  108.  
  109.         ArrayList<String> requestParameters = Collections.list(multipartRequest.getParameterNames());
  110.         for (String requestParameter : requestParameters) {
  111.             parts.add(requestParameter, multipartRequest.getParameter(requestParameter));
  112.         }
  113.  
  114.         headers.setContentType(MediaType.MULTIPART_FORM_DATA);
  115.  
  116.         return new HttpEntity<>(parts, headers);
  117.     }
  118.  
  119.     private void sendProxyRequest(HttpMethod method, HttpServletResponse servletResponse, URL targetUrl, URI uri, HttpEntity httpEntity) throws IOException {
  120.         RestTemplate restTemplate = restTemplateContextFactory.build();
  121.         try {
  122.             ResponseEntity<byte[]> exchange = restTemplate.exchange(uri, method, httpEntity, byte[].class);
  123.  
  124.             int responseStatusCode = exchange.getStatusCodeValue();
  125.             byte[] responseBody = exchange.getBody();
  126.             HttpHeaders responseHeaders = exchange.getHeaders();
  127.  
  128.             log.debug("{} responded with status code {}", targetUrl, responseStatusCode);
  129.  
  130.             copyProxyResponseToServletResponse(servletResponse, responseBody, responseHeaders, responseStatusCode);
  131.  
  132.         } catch(HttpStatusCodeException e) {
  133.             int proxyResponseStatusCode = e.getRawStatusCode();
  134.             byte[] responseBody = e.getResponseBodyAsByteArray();
  135.             HttpHeaders proxyResonseHeaders = e.getResponseHeaders();
  136.  
  137.             log.debug("FAILED: {} responded with status code {}", targetUrl, proxyResponseStatusCode);
  138.  
  139.             copyProxyResponseToServletResponse(servletResponse, responseBody, proxyResonseHeaders, proxyResponseStatusCode);
  140.         }
  141.     }
  142.  
  143.     private void copyProxyResponseToServletResponse(HttpServletResponse response, byte[] bodyString, HttpHeaders proxyResonseHeaders, int proxyResponseStatusCode) throws IOException {
  144.         if(proxyResonseHeaders != null) {
  145.             proxyResonseHeaders.forEach((headerName, value) -> {
  146.                 if(shouldCopyResponseHeader(headerName)) {
  147.                     response.addHeader(headerName, String.join(",", value));
  148.                 }
  149.             });
  150.         }
  151.  
  152.         response.setStatus(proxyResponseStatusCode);
  153.         if(bodyString != null) {
  154.             IOUtils.copy(new ByteArrayInputStream(bodyString), response.getOutputStream());
  155.         }
  156.     }
  157.  
  158.     private boolean shouldCopyResponseHeader(String headerName) {
  159.         return headerName != null
  160.                 && !"Transfer-Encoding".equals(headerName);
  161.     }
  162.  
  163.     private URL getTargetUrl(HttpServletRequest request) {
  164.         try {
  165.             return targetUrlBuilder.buildUrl(request);
  166.         } catch (BlacklistedServiceException e) {
  167.             log.info("Blocking request to blacklisted service '{}'", e.getService());
  168.             return null;
  169.         } catch (Exception e) {
  170.             log.warn("Failed to determine target URL", e);
  171.             return null;
  172.         }
  173.     }
  174.  
  175.     class MultipartInputStreamFileResource extends InputStreamResource {
  176.  
  177.         private final String filename;
  178.  
  179.         MultipartInputStreamFileResource(InputStream inputStream, String filename) {
  180.             super(inputStream);
  181.             this.filename = filename;
  182.         }
  183.  
  184.         @Override
  185.         public String getFilename() {
  186.             return this.filename;
  187.         }
  188.  
  189.         @Override
  190.         public long contentLength() throws IOException {
  191.             return -1;
  192.         }
  193.     }
  194.  
  195. }
RAW Paste Data