// ProxyHandler throws INTERNAL_SERVER_ERRORS without isRecoverable() check.
  @Test
  public void testRecoverableRewritingException() throws Exception {
    String url = "http://example.org/mypage.html";
    String domain = "example.org";

    setupProxyRequestMock(domain, url, true, -1, null, null);

    String contentType = "text/html; charset=UTF-8";
    HttpResponse resp =
        new HttpResponseBuilder()
            .setResponseString("Hello")
            .addHeader("Content-Type", contentType)
            .create();

    expect(pipeline.execute((HttpRequest) EasyMock.anyObject())).andReturn(resp);

    replay();

    final StringBuilder stringBuilder = new StringBuilder("");
    ResponseRewriter rewriter = getResponseRewriterThatThrowsExceptions(stringBuilder);

    ResponseRewriterRegistry rewriterRegistry =
        new DefaultResponseRewriterRegistry(Arrays.<ResponseRewriter>asList(rewriter), null);
    ProxyHandler proxyHandler = new ProxyHandler(pipeline, rewriterRegistry, true);

    request.setReturnOriginalContentOnError(true);
    HttpResponse recorder = proxyHandler.fetch(request);

    verify();

    // Ensure that original content is returned.
    assertEquals(recorder.getHeader("Content-Type"), contentType);
    assertEquals("Hello", recorder.getResponseAsString());
    assertEquals("exceptionThrown", stringBuilder.toString());
  }
  private void expectMime(String expectedMime, String contentMime, String outputMime)
      throws Exception {
    String url =
        "http://example.org/file.img?" + Param.REWRITE_MIME_TYPE.getKey() + '=' + expectedMime;
    String domain = "example.org";

    setupProxyRequestMock(domain, url, false, -1, expectedMime, null);

    HttpRequest req = new HttpRequest(Uri.parse(url)).setRewriteMimeType(expectedMime);

    HttpResponse resp =
        new HttpResponseBuilder()
            .setResponseString("Hello")
            .addHeader("Content-Type", contentMime)
            .create();

    expect(pipeline.execute(req)).andReturn(resp);

    replay();
    HttpResponse response = proxyHandler.fetch(request);
    verify();

    assertEquals(outputMime, response.getHeader("Content-Type"));
    reset();
  }
  @Test
  public void testInvalidHeaderDropped() throws Exception {
    String url = "http://example.org/mypage.html";
    String domain = "example.org";

    setupProxyRequestMock(domain, url, true, -1, null, null);

    HttpRequest req = new HttpRequest(Uri.parse(url)).setIgnoreCache(true);
    String contentType = "text/html; charset=UTF-8";
    HttpResponse resp =
        new HttpResponseBuilder()
            .setResponseString("Hello")
            .addHeader("Content-Type", contentType)
            .addHeader("Content-Length", "200") // Disallowed header.
            .addHeader(":", "someDummyValue") // Invalid header name.
            .create();

    expect(pipeline.execute(req)).andReturn(resp);

    replay();

    HttpResponse recorder = proxyHandler.fetch(request);

    verify();
    assertNull(recorder.getHeader(":"));
    assertNull(recorder.getHeader("Content-Length"));
    assertEquals(recorder.getHeader("Content-Type"), contentType);
  }
  @Test
  public void testLockedDomainEmbed() throws Exception {
    setupNoArgsProxyRequestMock("www.example.com", URL_ONE);
    expectGetAndReturnData(URL_ONE, DATA_ONE.getBytes());

    replay();
    HttpResponse response = proxyHandler.fetch(request);
    verify();

    assertEquals(DATA_ONE, response.getResponseAsString());
    assertTrue(rewriter.responseWasRewritten());
  }
Example #5
0
  @Override
  public void fetch(HttpServletRequest request, HttpServletResponse response)
      throws IOException, GadgetException {
    if (request.getHeader("If-Modified-Since") != null) {
      response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
      return;
    }

    String host = request.getHeader("Host");
    if (!lockedDomainService.isSafeForOpenProxy(host)) {
      // Force embedded images and the like to their own domain to avoid XSS
      // in gadget domains.
      String msg =
          "Embed request for url "
              + getParameter(request, URL_PARAM, "")
              + " made to wrong domain "
              + host;
      logger.info(msg);
      throw new GadgetException(GadgetException.Code.INVALID_PARAMETER, msg);
    }

    HttpRequest rcr = buildHttpRequest(request);
    HttpResponse results = fetcher.fetch(rcr);
    if (contentRewriterRegistry != null) {
      results = contentRewriterRegistry.rewriteHttpResponse(rcr, results);
    }

    setResponseHeaders(request, response, results);

    for (Map.Entry<String, List<String>> entry : results.getHeaders().entrySet()) {
      String name = entry.getKey();
      if (!DISALLOWED_RESPONSE_HEADERS.contains(name.toLowerCase())) {
        for (String value : entry.getValue()) {
          response.addHeader(name, value);
        }
      }
    }

    if (rcr.getRewriteMimeType() != null) {
      response.setContentType(rcr.getRewriteMimeType());
    }

    if (results.getHttpStatusCode() != HttpResponse.SC_OK) {
      response.sendError(results.getHttpStatusCode());
    }

    IOUtils.copy(results.getResponse(), response.getOutputStream());
  }
  @Test
  public void testOctetSetOnNullContentType() throws Exception {
    String url = "http://example.org/file.evil";
    String domain = "example.org";

    setupNoArgsProxyRequestMock(domain, url);
    expectGetAndReturnHeaders(url, Maps.<String, List<String>>newHashMap());

    replay();
    HttpResponse response = proxyHandler.fetch(request);
    verify();

    assertEquals("application/octet-stream", response.getHeader("Content-Type"));
    assertNotNull(response.getHeader("Content-Disposition"));
    assertTrue(rewriter.responseWasRewritten());
  }
 public static String getMimeType(HttpRequest request, HttpResponse original) {
   String mimeType = request.getRewriteMimeType();
   if (mimeType == null) {
     mimeType = original.getHeader("Content-Type");
   }
   return mimeType != null ? mimeType.toLowerCase() : null;
 }
 /** {@inheritDoc} */
 public HttpResponse fetch(HttpRequest request) {
   if (!whitelist.allows(request.getUri().toJavaUri())) {
     log.warn(
         "A request to "
             + request.getUri()
             + " has been denied.  To allow requests to this URL add the application URL to your whitelist (http://confluence.atlassian.com/x/KQfCDQ ).");
     return new HttpResponseBuilder()
         .setHttpStatusCode(HttpResponse.SC_FORBIDDEN)
         .setHeader("Content-Type", "text/plain")
         .setResponseString(
             "Requests to "
                 + request.getUri()
                 + " are not allowed.  See your administrator about configuring a whitelist entry for this destination (http://confluence.atlassian.com/x/KQfCDQ ).")
         .create();
   }
   HttpCacheKey cacheKey = new HttpCacheKey(request);
   HttpResponse response = cache.getResponse(cacheKey, request);
   if (response != null) {
     return response;
   }
   try {
     HttpUriRequest hcRequest = newHcRequest(request);
     if (request.getPostBodyLength() > 0) {
       ((HttpEntityEnclosingRequest) hcRequest)
           .setEntity(new InputStreamEntity(request.getPostBody(), request.getPostBodyLength()));
     }
     org.apache.http.HttpResponse hcResponse;
     try {
       // first try with TLS, the most common SSL protocol
       hcResponse = newHttpClient("TLSv1", request).execute(hcRequest);
     } catch (SSLException e) {
       log.debug(
           "SSL Exception establishing connection with TLSv1 protocol. Falling back to SSLv3.", e);
       // if TLS failed, try with SSLv3
       hcResponse = newHttpClient("SSLv3", request).execute(hcRequest);
     }
     response = makeResponse(hcResponse);
     return cache.addResponse(cacheKey, request, response);
   } catch (IOException e) {
     if (e instanceof java.net.SocketTimeoutException || e instanceof java.net.SocketException) {
       return HttpResponse.timeout();
     } else {
       log.error("Unable to retrieve response", e);
     }
     return HttpResponse.error();
   }
 }
  private void assertNoContentDispositionForFlash(String contentType) throws Exception {
    // Some headers may be blacklisted. These are OK.
    String url = "http://example.org/file.evil";
    String domain = "example.org";
    Map<String, List<String>> headers = ImmutableMap.of("Content-Type", Arrays.asList(contentType));

    setupNoArgsProxyRequestMock(domain, url);
    expectGetAndReturnHeaders(url, headers);

    replay();
    HttpResponse response = proxyHandler.fetch(request);
    verify();

    assertEquals(contentType, response.getHeader("Content-Type"));
    assertNull(response.getHeader("Content-Disposition"));
    assertTrue(rewriter.responseWasRewritten());
  }
  @Test
  public void doPostHttpError() throws Exception {
    setupPost();
    expect(fixture.httpFetcher.fetch(request)).andReturn(HttpResponse.notFound());
    fixture.replay();

    servlet.doGet(fixture.request, recorder);

    assertResponseOk(HttpResponse.SC_NOT_FOUND, "");
  }
  @Test
  public void testHttpRequestFillsParentAndContainer() throws Exception {
    setupNoArgsProxyRequestMock("www.example.com", URL_ONE);
    // HttpRequest req = new HttpRequest(Uri.parse(URL_ONE));
    HttpResponse resp = new HttpResponseBuilder().setResponse(DATA_ONE.getBytes()).create();

    Capture<HttpRequest> httpRequest = new Capture<HttpRequest>();
    expect(pipeline.execute(capture(httpRequest))).andReturn(resp);

    replay();
    HttpResponse response = proxyHandler.fetch(request);
    verify();

    // Check that the HttpRequest passed in has all the relevant fields sets
    assertEquals("default", httpRequest.getValue().getContainer());
    assertEquals(Uri.parse(URL_ONE), httpRequest.getValue().getUri());

    assertEquals(DATA_ONE, response.getResponseAsString());
    assertTrue(rewriter.responseWasRewritten());
  }
 /**
  * We don't actually rewrite the image we just ensure that it is in fact a valid and known image
  * type.
  */
 private boolean rewriteProxiedImage(
     HttpRequest request, HttpResponse resp, MutableContent content) {
   boolean imageIsSafe = false;
   try {
     String contentType = resp.getHeader("Content-Type");
     if (contentType == null || contentType.toLowerCase().startsWith("image/")) {
       // Unspecified or unknown image mime type.
       try {
         ImageFormat imageFormat =
             Sanselan.guessFormat(
                 new ByteSourceInputStream(resp.getResponse(), request.getUri().getPath()));
         if (imageFormat == ImageFormat.IMAGE_FORMAT_UNKNOWN) {
           logger.log(
               Level.INFO, "Unable to sanitize unknown image type " + request.getUri().toString());
           return true;
         }
         imageIsSafe = true;
         // Return false to indicate that no rewriting occurred
         return false;
       } catch (IOException ioe) {
         throw new RuntimeException(ioe);
       } catch (ImageReadException ire) {
         // Unable to read the image so its not safe
         logger.log(
             Level.INFO,
             "Unable to detect image type for "
                 + request.getUri().toString()
                 + " for sanitized content",
             ire);
         return true;
       }
     } else {
       return true;
     }
   } finally {
     if (!imageIsSafe) {
       content.setContent("");
     }
   }
 }
  @Test
  public void testHeadersPreserved() throws Exception {
    // Some headers may be blacklisted. These are OK.
    String url = "http://example.org/file.evil";
    String domain = "example.org";
    String contentType = "text/evil; charset=UTF-8";
    String magicGarbage = "fadfdfdfd";
    Map<String, List<String>> headers = Maps.newHashMap();
    headers.put("Content-Type", Arrays.asList(contentType));
    headers.put("X-Magic-Garbage", Arrays.asList(magicGarbage));

    setupNoArgsProxyRequestMock(domain, url);
    expectGetAndReturnHeaders(url, headers);

    replay();
    HttpResponse response = proxyHandler.fetch(request);
    verify();

    assertEquals(contentType, response.getHeader("Content-Type"));
    assertEquals(magicGarbage, response.getHeader("X-Magic-Garbage"));
    assertTrue(rewriter.responseWasRewritten());
  }
  @Test
  public void testGetFallback() throws Exception {
    String url = "http://example.org/file.evil";
    String domain = "example.org";
    String fallback_url = "http://fallback.com/fallback.png";

    setupProxyRequestMock(domain, url, true, -1, null, fallback_url);

    HttpRequest req = new HttpRequest(Uri.parse(url)).setIgnoreCache(true);
    HttpResponse resp = HttpResponse.error();
    HttpResponse fallback_resp = new HttpResponse("Fallback");
    expect(pipeline.execute(req)).andReturn(resp);
    expect(pipeline.execute(isA(HttpRequest.class))).andReturn(fallback_resp);

    replay();
    proxyHandler.fetch(request);
    verify();
  }
  /** Sanitize a CSS file. */
  private boolean rewriteProxiedCss(
      HttpRequest request,
      HttpResponse response,
      MutableContent content,
      ContentRewriterFeature rewriterFeature) {
    String sanitized = "";
    try {
      String contentType = response.getHeader("Content-Type");
      if (contentType == null || contentType.toLowerCase().startsWith("text/")) {
        SanitizingProxyingLinkRewriter cssImportRewriter =
            sanitizingProxyingLinkRewriterFactory.create(
                request.getGadget(),
                rewriterFeature,
                request.getContainer(),
                "text/css",
                false,
                request.getIgnoreCache());
        SanitizingProxyingLinkRewriter cssImageRewriter =
            sanitizingProxyingLinkRewriterFactory.create(
                request.getGadget(),
                rewriterFeature,
                request.getContainer(),
                "image/*",
                false,
                request.getIgnoreCache());
        sanitized =
            cssSanitizer.sanitize(
                content.getContent(), request.getUri(), cssImportRewriter, cssImageRewriter);
      }

      return true;
    } finally {
      // Set sanitized content in finally to ensure it is always cleared in
      // the case of errors
      content.setContent(sanitized);
    }
  }