You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shindig.apache.org by zh...@apache.org on 2010/10/08 01:19:52 UTC
svn commit: r1005661 - in /shindig/trunk/java/gadgets/src:
main/java/org/apache/shindig/gadgets/rewrite/
main/java/org/apache/shindig/gadgets/servlet/
main/java/org/apache/shindig/gadgets/uri/
test/java/org/apache/shindig/gadgets/rewrite/ test/java/org...
Author: zhoresh
Date: Thu Oct 7 23:19:52 2010
New Revision: 1005661
URL: http://svn.apache.org/viewvc?rev=1005661&view=rev
Log:
Ref: http://codereview.appspot.com/2298042/
Proxy should use resource TTL by default
Modified:
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java
shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureTestCase.java
shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyHandlerTest.java
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java?rev=1005661&r1=1005660&r2=1005661&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeature.java Thu Oct 7 23:19:52 2010
@@ -55,13 +55,13 @@ public class ContentRewriterFeature {
protected static final String EXCLUDE_URL = "exclude-url";
protected static final String INCLUDE_TAGS = "include-tags";
protected static final String EXPIRES = "expires";
-
- public static final Integer EXPIRES_DEFAULT = -1; // -1 = Use HTTP.
+
+ public static final Integer EXPIRES_HTTP = -1; // -1 = Use HTTP.
protected enum PatternOptions {
ALL, NONE, REGEX, STRINGS
}
-
+
/**
* Factory for content rewriter features.
*/
@@ -79,7 +79,7 @@ public class ContentRewriterFeature {
public Config getDefault() {
return defaultConfig;
}
-
+
public Config get(HttpRequest request) {
return get(request.getGadget());
}
@@ -124,7 +124,7 @@ public class ContentRewriterFeature {
"", false, true);
}
}
-
+
@Singleton
public static class DefaultConfig extends Config {
@Inject
@@ -138,7 +138,7 @@ public class ContentRewriterFeature {
super(includeUrls, excludeUrls, expires, includeTags, onlyAllowExcludes, enableSplitJsConcat);
}
}
-
+
public static class Config {
private final MatchBundle includes;
private final MatchBundle excludes;
@@ -151,7 +151,7 @@ public class ContentRewriterFeature {
private final Integer expires;
private final boolean onlyAllowExcludes;
private final boolean enableSplitJs;
-
+
// Lazily computed
private Integer fingerprint;
private static final Pattern COMMA_WHITESPACE_PATTERN = Pattern.compile("\\s*,\\s*");
@@ -159,7 +159,7 @@ public class ContentRewriterFeature {
/**
* Constructor which takes a gadget spec and container settings
* as "raw" input strings.
- *
+ *
* @param defaultInclude As a regex
* @param defaultExclude As a regex
* @param defaultExpires Either "HTTP" or a ttl in seconds
@@ -173,7 +173,7 @@ public class ContentRewriterFeature {
// Set up includes from defaultInclude param
this.includes = getMatchBundle(paramTrim(defaultInclude),
Collections.<String>emptyList());
-
+
// Set up excludes from defaultExclude param
this.excludes = getMatchBundle(paramTrim(defaultExclude),
Collections.<String>emptyList());
@@ -186,26 +186,26 @@ public class ContentRewriterFeature {
}
}
this.includeTags = includeTagsBuilder.build();
-
+
// Parse expires field
- int expiresVal = EXPIRES_DEFAULT;
+ int expiresVal = EXPIRES_HTTP;
try {
expiresVal = Integer.parseInt(paramTrim(defaultExpires));
} catch (NumberFormatException e) {
// Fall through to default.
}
this.expires = expiresVal;
-
+
// Save config for onlyAllowExcludes
this.onlyAllowExcludes = onlyAllowExcludes;
this.enableSplitJs = enableSplitJs;
}
-
+
Config(GadgetSpec spec, Config defaultConfig) {
this.onlyAllowExcludes = defaultConfig.onlyAllowExcludes;
-
+
Feature f = spec.getModulePrefs().getFeatures().get("content-rewrite");
-
+
// Include overrides.
// Note: Shindig originally supported the plural versions with regular
// expressions. But the OpenSocial specification v0.9 allows for singular
@@ -224,7 +224,7 @@ public class ContentRewriterFeature {
}
}
this.includes = getMatchBundle(includeRegex, includeUrls);
-
+
// Exclude overrides. Only use the exclude regex specified by the
// gadget spec if !onlyAllowExcludes.
String excludeRegex = defaultConfig.excludes.param;
@@ -239,7 +239,7 @@ public class ContentRewriterFeature {
}
}
this.excludes = getMatchBundle(excludeRegex, excludeUrls);
-
+
// Spec-specified include tags.
Set<String> tagsVal = null;
if (f != null && f.getParams().containsKey(INCLUDE_TAGS)) {
@@ -264,31 +264,32 @@ public class ContentRewriterFeature {
if (f != null && f.getParams().containsKey(EXPIRES)) {
try {
int overrideVal = Integer.parseInt(f.getParam(EXPIRES));
- expiresVal = Math.min(overrideVal, expiresVal);
+ expiresVal = (expiresVal == EXPIRES_HTTP || overrideVal < expiresVal) ?
+ overrideVal : expiresVal;
} catch (NumberFormatException e) {
// Falls through to default.
if ("HTTP".equalsIgnoreCase(f.getParam(EXPIRES).trim())) {
- expiresVal = EXPIRES_DEFAULT;
+ expiresVal = EXPIRES_HTTP;
}
}
}
this.expires = expiresVal;
this.enableSplitJs = defaultConfig.enableSplitJs;
}
-
+
private String paramTrim(String param) {
if (param == null) {
return param;
}
-
+
return param.trim();
}
-
+
private MatchBundle getMatchBundle(String regex, Collection<String> matches) {
MatchBundle bundle = new MatchBundle();
bundle.param = regex;
bundle.matches = matches;
-
+
if (bundle.matches.isEmpty() && StringUtils.isEmpty(bundle.param)) {
bundle.options = PatternOptions.NONE;
} else if (bundle.matches.size() == 1) {
@@ -312,7 +313,7 @@ public class ContentRewriterFeature {
}
return bundle;
}
-
+
private static class MatchBundle {
private String param;
private PatternOptions options;
@@ -327,7 +328,7 @@ public class ContentRewriterFeature {
protected boolean shouldExclude(String url) {
return matcherMatches(url, excludes);
}
-
+
private static boolean matcherMatches(String url, MatchBundle bundle) {
switch (bundle.options) {
case NONE:
@@ -374,7 +375,7 @@ public class ContentRewriterFeature {
public Integer getExpires() {
return expires;
}
-
+
public boolean isSplitJsEnabled() {
return enableSplitJs;
}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java?rev=1005661&r1=1005660&r2=1005661&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/servlet/ProxyHandler.java Thu Oct 7 23:19:52 2010
@@ -45,7 +45,6 @@ import java.io.IOException;
public class ProxyHandler {
// TODO: parameterize these.
static final Integer LONG_LIVED_REFRESH = (365 * 24 * 60 * 60); // 1 year
- static final Integer DEFAULT_REFRESH = (60 * 60); // 1 hour
private final RequestPipeline requestPipeline;
private final ResponseRewriterRegistry contentRewriterRegistry;
@@ -109,7 +108,8 @@ public class ProxyHandler {
try {
ServletUtil.setCachingHeaders(response,
- proxyUri.translateStatusRefresh(LONG_LIVED_REFRESH, DEFAULT_REFRESH), false);
+ proxyUri.translateStatusRefresh(LONG_LIVED_REFRESH, (int) (results.getCacheTtl() / 1000)),
+ false);
} catch (GadgetException gex) {
return ServletUtil.errorResponse(gex);
}
Modified: shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java?rev=1005661&r1=1005660&r2=1005661&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java (original)
+++ shindig/trunk/java/gadgets/src/main/java/org/apache/shindig/gadgets/uri/ProxyUriBase.java Thu Oct 7 23:19:52 2010
@@ -45,7 +45,7 @@ public class ProxyUriBase {
private String rewriteMimeType = null;
private boolean sanitizeContent = false;
private boolean cajoleContent = false;
-
+
protected ProxyUriBase(Gadget gadget) {
this(null, // Meaningless in "context" mode. translateStatusRefresh invalid here.
getIntegerValue(gadget.getContext().getParameter(Param.REFRESH.getKey())),
@@ -54,7 +54,7 @@ public class ProxyUriBase {
gadget.getContext().getContainer(),
gadget.getSpec().getUrl().toString());
}
-
+
protected ProxyUriBase(UriStatus status, Uri origUri) {
this.status = status;
setFromUri(origUri);
@@ -89,8 +89,8 @@ public class ProxyUriBase {
gadget = uri.getQueryParameter(Param.GADGET.getKey());
rewriteMimeType = uri.getQueryParameter(Param.REWRITE_MIME_TYPE.getKey());
sanitizeContent = getBooleanValue(uri.getQueryParameter(Param.SANITIZE.getKey()));
- cajoleContent = getBooleanValue(uri.getQueryParameter(Param.CAJOLE.getKey()));
- }
+ cajoleContent = getBooleanValue(uri.getQueryParameter(Param.CAJOLE.getKey()));
+ }
}
@Override
@@ -99,7 +99,7 @@ public class ProxyUriBase {
return true;
}
if (!(obj instanceof ProxyUriBase)) {
- return false;
+ return false;
}
ProxyUriBase objUri = (ProxyUriBase) obj;
return (Objects.equal(this.status, objUri.status)
@@ -124,7 +124,7 @@ public class ProxyUriBase {
this.rewriteMimeType = type;
return this;
}
-
+
public ProxyUriBase setSanitizeContent(boolean sanitize) {
this.sanitizeContent = sanitize;
return this;
@@ -134,7 +134,7 @@ public class ProxyUriBase {
this.cajoleContent = cajole;
return this;
}
-
+
public UriStatus getStatus() {
return status;
}
@@ -162,7 +162,7 @@ public class ProxyUriBase {
public String getRewriteMimeType() {
return rewriteMimeType;
}
-
+
public boolean sanitizeContent() {
return sanitizeContent;
}
@@ -195,20 +195,20 @@ public class ProxyUriBase {
req.setRewriteMimeType(getRewriteMimeType());
}
req.setSanitizationRequested(sanitizeContent());
- req.setCajaRequested(cajoleContent());
+ req.setCajaRequested(cajoleContent());
return req;
}
/**
- * Construct the query parameters for proxy url
- * @param forcedRefresh optional overwrite the refresh time
+ * Construct the query parameters for proxy url
+ * @param forcedRefresh optional overwrite the refresh time
* @param version optional version
* @return Url with only query parameters set
*/
public UriBuilder makeQueryParams(Integer forcedRefresh, String version) {
UriBuilder queryBuilder = new UriBuilder();
-
+
// Add all params common to both chained and query syntax.
String container = getContainer();
queryBuilder.addQueryParameter(Param.CONTAINER.getKey(), container);
@@ -219,7 +219,7 @@ public class ProxyUriBase {
if (forcedRefresh != null && forcedRefresh >= 0) {
queryBuilder.addQueryParameter(Param.REFRESH.getKey(), forcedRefresh.toString());
} else if (getRefresh() != null) {
- queryBuilder.addQueryParameter(Param.REFRESH.getKey(), getRefresh().toString());
+ queryBuilder.addQueryParameter(Param.REFRESH.getKey(), getRefresh().toString());
}
}
@@ -238,7 +238,19 @@ public class ProxyUriBase {
return queryBuilder;
}
- public Integer translateStatusRefresh(int longVal, int defaultVal)
+ /**
+ * Calculate cache time for a resource url. Provide long period for versioned resource,
+ * use original value for unversioned resource, and no cache for invalid versions.
+ * Invalid version can happen in multiple instances environemnt where the url can be
+ * created on one server and the actually retreival is done on another that have an older version
+ * of resource in cache. In that case no caching will cause the user browser to try again next
+ * time and hopefully getting the newer version.
+ * @param longVal long expiry for versioned resource
+ * @param originalResourceTtl original resource ttl, to be served fro unversion resource
+ * @return the calculated expiry to the Uri according to status
+ * @throws GadgetException
+ */
+ public Integer translateStatusRefresh(int longVal, int originalResourceTtl)
throws GadgetException {
Integer retRefresh = 0;
switch (getStatus()) {
@@ -246,7 +258,7 @@ public class ProxyUriBase {
retRefresh = longVal;
break;
case VALID_UNVERSIONED:
- retRefresh = defaultVal;
+ retRefresh = originalResourceTtl;
break;
case INVALID_VERSION:
retRefresh = 0;
@@ -275,7 +287,7 @@ public class ProxyUriBase {
protected static boolean getBooleanValue(String str) {
return str != null && "1".equals(str);
}
-
+
protected static Integer getIntegerValue(String str) {
Integer val = null;
try {
Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureTestCase.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureTestCase.java?rev=1005661&r1=1005660&r2=1005661&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureTestCase.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/rewrite/ContentRewriterFeatureTestCase.java Thu Oct 7 23:19:52 2010
@@ -136,7 +136,39 @@ public class ContentRewriterFeatureTestC
defaultRewriterFeature = new ContentRewriterFeature.Config(
createSpecWithRewrite("test\\.com", "testx", "htTp ", tags),
new ContentRewriterFeature.DefaultConfig("", "", "12345", TAGS, false, false));
- assertEquals(ContentRewriterFeature.EXPIRES_DEFAULT, defaultRewriterFeature.getExpires());
+ assertEquals(ContentRewriterFeature.EXPIRES_HTTP, defaultRewriterFeature.getExpires());
+ }
+
+ @Test
+ public void testExpiresOverwriteTooBig() throws Exception {
+ defaultRewriterFeature = new ContentRewriterFeature.Config(
+ createSpecWithRewrite("test\\.com", "testx", "20000", tags),
+ new ContentRewriterFeature.DefaultConfig("", "", "12345", TAGS, false, false));
+ assertEquals(12345, defaultRewriterFeature.getExpires().intValue());
+ }
+
+ @Test
+ public void testExpiresBadValue() throws Exception {
+ defaultRewriterFeature = new ContentRewriterFeature.Config(
+ createSpecWithRewrite("test\\.com", "testx", "X", tags),
+ new ContentRewriterFeature.DefaultConfig("", "", "12345", TAGS, false, false));
+ assertEquals(12345, defaultRewriterFeature.getExpires().intValue());
+ }
+
+ @Test
+ public void testExpiresOverwrite() throws Exception {
+ defaultRewriterFeature = new ContentRewriterFeature.Config(
+ createSpecWithRewrite("test\\.com", "testx", "10", tags),
+ new ContentRewriterFeature.DefaultConfig("", "", "12345", TAGS, false, false));
+ assertEquals(10, defaultRewriterFeature.getExpires().intValue());
+ }
+
+ @Test
+ public void testExpiresOverwriteDefault() throws Exception {
+ defaultRewriterFeature = new ContentRewriterFeature.Config(
+ createSpecWithRewrite("test\\.com", "testx", "10", tags),
+ new ContentRewriterFeature.DefaultConfig("", "", "-1", TAGS, false, false));
+ assertEquals(10, defaultRewriterFeature.getExpires().intValue());
}
@Test
@@ -187,14 +219,14 @@ public class ContentRewriterFeatureTestC
assertTrue(defaultRewriterFeature.shouldRewriteURL("http://www.foobar.com"));
assertFalse(defaultRewriterFeature.shouldRewriteURL("http://www.test.com"));
}
-
+
@Test
public void testSplitJsSupported() throws Exception {
defaultRewriterFeature =
new ContentRewriterFeature.DefaultConfig("", "test", "0", TAGS, false, true);
assertTrue(defaultRewriterFeature.isSplitJsEnabled());
}
-
+
@Test
public void testSplitJsNotSupported() throws Exception {
defaultRewriterFeature =
Modified: shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyHandlerTest.java
URL: http://svn.apache.org/viewvc/shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyHandlerTest.java?rev=1005661&r1=1005660&r2=1005661&view=diff
==============================================================================
--- shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyHandlerTest.java (original)
+++ shindig/trunk/java/gadgets/src/test/java/org/apache/shindig/gadgets/servlet/ProxyHandlerTest.java Thu Oct 7 23:19:52 2010
@@ -23,6 +23,7 @@ import com.google.common.collect.Maps;
import org.apache.shindig.common.EasyMockTestCase;
import org.apache.shindig.common.uri.Uri;
+import org.apache.shindig.common.util.FakeTimeSource;
import org.apache.shindig.config.ContainerConfig;
import org.apache.shindig.gadgets.Gadget;
import org.apache.shindig.gadgets.GadgetException;
@@ -59,10 +60,10 @@ public class ProxyHandlerTest extends Ea
public ResponseRewriterRegistry rewriterRegistry
= new DefaultResponseRewriterRegistry(Arrays.<ResponseRewriter>asList(rewriter), null);
private ProxyUriManager.ProxyUri request;
-
+
private final ProxyHandler proxyHandler
= new ProxyHandler(pipeline, rewriterRegistry, true);
-
+
private void expectGetAndReturnData(String url, byte[] data) throws Exception {
HttpRequest req = new HttpRequest(Uri.parse(url));
HttpResponse resp = new HttpResponseBuilder().setResponse(data).create();
@@ -75,7 +76,7 @@ public class ProxyHandlerTest extends Ea
HttpResponse resp = new HttpResponseBuilder().addAllHeaders(headers).create();
expect(pipeline.execute(req)).andReturn(resp);
}
-
+
private void setupProxyRequestMock(String host, String url,
boolean noCache, int refresh, String rewriteMime, String fallbackUrl) throws Exception {
request = new ProxyUriManager.ProxyUri(
@@ -93,12 +94,14 @@ public class ProxyHandlerTest extends Ea
private ResponseRewriter getResponseRewriterThatThrowsExceptions(
final StringBuilder stringBuilder) {
return new DomWalker.Rewriter() {
+ @Override
public void rewrite(Gadget gadget, MutableContent content)
throws RewritingException {
stringBuilder.append("exceptionThrown");
throw new RewritingException("sad", 404);
}
+ @Override
public void rewrite(HttpRequest request, HttpResponseBuilder builder)
throws RewritingException {
stringBuilder.append("exceptionThrown");
@@ -140,7 +143,7 @@ public class ProxyHandlerTest extends Ea
public void testLockedDomainEmbed() throws Exception {
setupNoArgsProxyRequestMock("www.example.com", URL_ONE);
expectGetAndReturnData(URL_ONE, DATA_ONE.getBytes());
-
+
replay();
HttpResponse response = proxyHandler.fetch(request);
verify();
@@ -201,7 +204,7 @@ public class ProxyHandlerTest extends Ea
assertEquals(magicGarbage, response.getHeader("X-Magic-Garbage"));
assertTrue(rewriter.responseWasRewritten());
}
-
+
@Test
public void testOctetSetOnNullContentType() throws Exception {
String url = "http://example.org/file.evil";
@@ -218,7 +221,7 @@ public class ProxyHandlerTest extends Ea
assertNotNull(response.getHeader("Content-Disposition"));
assertTrue(rewriter.responseWasRewritten());
}
-
+
@Test
public void testNoContentDispositionForFlash() throws Exception {
// Some headers may be blacklisted. These are OK.
@@ -238,7 +241,7 @@ public class ProxyHandlerTest extends Ea
assertNull(response.getHeader("Content-Disposition"));
assertTrue(rewriter.responseWasRewritten());
}
-
+
@Test
public void testGetFallback() throws Exception {
String url = "http://example.org/file.evil";
@@ -379,15 +382,18 @@ public class ProxyHandlerTest extends Ea
public void testWithCache() throws Exception {
String url = "http://example.org/file.evil";
String domain = "example.org";
+ HttpResponse.setTimeSource(new FakeTimeSource());
setupProxyRequestMock(domain, url, false, 120, null, null);
-
+
HttpRequest req = new HttpRequestCache(Uri.parse(url)).setCacheTtl(120).setIgnoreCache(false);
- HttpResponse resp = new HttpResponse("Hello");
- expect(pipeline.execute(req)).andReturn(resp);
+ HttpResponseBuilder resp = new HttpResponseBuilder().setCacheTtl(1234);
+ resp.setContent("Hello");
+ expect(pipeline.execute(req)).andReturn(resp.create());
replay();
- proxyHandler.fetch(request);
+ HttpResponse proxyResp = proxyHandler.fetch(request);
+ assertEquals(120, proxyResp.getCacheTtl() / 1000);
verify();
}
@@ -395,15 +401,18 @@ public class ProxyHandlerTest extends Ea
public void testWithBadTtl() throws Exception {
String url = "http://example.org/file.evil";
String domain = "example.org";
+ HttpResponse.setTimeSource(new FakeTimeSource());
setupProxyRequestMock(domain, url, false, -1, null, null);
-
+
HttpRequest req = new HttpRequestCache(Uri.parse(url)).setCacheTtl(-1).setIgnoreCache(false);
- HttpResponse resp = new HttpResponse("Hello");
- expect(pipeline.execute(req)).andReturn(resp);
+ HttpResponseBuilder resp = new HttpResponseBuilder().setCacheTtl(1234);
+ resp.setContent("Hello");
+ expect(pipeline.execute(req)).andReturn(resp.create());
replay();
- proxyHandler.fetch(request);
+ HttpResponse proxyResp = proxyHandler.fetch(request);
+ assertEquals(1234, proxyResp.getCacheTtl() / 1000);
verify();
}
@@ -414,7 +423,7 @@ public class ProxyHandlerTest extends Ea
String domain = "example.org";
setupProxyRequestMock(domain, url, false, -1, expectedMime, null);
-
+
HttpRequest req = new HttpRequest(Uri.parse(url))
.setRewriteMimeType(expectedMime);
@@ -424,11 +433,11 @@ public class ProxyHandlerTest extends Ea
.create();
expect(pipeline.execute(req)).andReturn(resp);
-
+
replay();
HttpResponse response = proxyHandler.fetch(request);
verify();
-
+
assertEquals(outputMime, response.getHeader("Content-Type"));
reset();
}