I'm trying to develop code that can filter requests, modify them, etc. The Proxy intercepts requests correctly and is able to display the correct Uri for example. However, I cannot read the contents of the http package. In fact, the request.content (). ReadableBytes () function returns 0.
below the code:
HttpProxyServer server =
DefaultHttpProxyServer.bootstrap()
.withAddress(new InetSocketAddress("localhost", 8080))
.withTransparent(true)
.withFiltersSource(new HttpFiltersSourceAdapter() {
#Override
public int getMaximumRequestBufferSizeInBytes() {
return 512 * 1024;
}
#Override
public int getMaximumResponseBufferSizeInBytes() {
return 50 * 1024 * 1024;
}
public HttpFilters filterRequest(HttpRequest originalRequest, ChannelHandlerContext ctx) {
return new HttpFiltersAdapter(originalRequest) {
#Override
public HttpResponse clientToProxyRequest(HttpObject httpObject) {
FullHttpRequest request = (FullHttpRequest) httpObject;
CompositeByteBuf contentBuf = (CompositeByteBuf) request.content();
System.out.println(request.getUri());
System.out.println(request.content().readableBytes());
So the question is: why i can't read the body of the request?
Related
#Slf4j
public class DownloadImg {
private final WebClient webClient;
private final Vertx vertx;
public DownloadImg(Vertx vertx) {
WebClientOptions newOptions = new WebClientOptions();
newOptions.setDefaultPort(12345);
newOptions.setDefaultHost("localhost");
webClient = WebClient.create(vertx,newOptions);
this.vertx = vertx;
}
public void download(String scm, String version) {
String file = String.format("/%s_%s.tar.gz", scm.replace("/", "."), version);
webClient.get("url_for_file")
.send(it -> {
it.result();// i acully
});
}
}
I do get all the file data, but I want to handle those data by stream API in case the file is too large or OOM exception.
any idea?
I am running WebAPI with just one Middleware and not able to set response HTTP status code.
I am using OnSendingHeaders() and able to add headers and set response body, but status code is not getting set and response always has it set as 200 OK.
I am able to set response status code in ValidateUrl(context) though. Difference is ValidateUrl(context) is called synchronously and OnSendingHeaders() would be called asynchronously after ProcessIncomingRequest() is executed.
Is HTTP status line being sent even before OnSendingHeaders() gets called?
How/where should I set response HTTP status code when incoming request is being processed asynchronously?
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
appBuilder.Use(typeof(SampleMiddleware));
}
}
public class SampleMiddleware : OwinMiddleware
{
private string _responseBody = null;
public SampleMiddleware(OwinMiddleware next) : base(next)
{
}
public async override Task Invoke(IOwinContext context)
{
if (!ValidateUrl(context))
{
return;
}
context.Response.OnSendingHeaders(state =>
{
var cntxt = (IOwinContext)state;
SetResponseMessage(cntxt);
}, context);
await ProcessIncomingRequest();
await Next.Invoke(context);
}
private void SetResponseMessage(IOwinContext context)
{
//Setting status code
context.Response.StatusCode = 201;
//Setting headers
context.Response.Headers.Add("XYZ", new[] { "Value-1" });
context.Response.Headers.Add("ABC", new[] { "Value-2" });
//Setting response body
context.Response.Write(_responseBody);
}
private async Task ProcessIncomingRequest()
{
// Process request
//await ProcessingFunc();
// Set response body
_responseBody = "Response body based on above processing";
}
private bool ValidateUrl(IOwinContext context)
{
if (context.Request.Host.ToString().Equals("xyx"))
{
return true;
}
else
{
context.Response.StatusCode = 400;
context.Response.Write("Bad Request");
return false;
}
}
}
org.springframework.cloud.contract.spec.Contract.make {
request {
method 'GET'
url '/weather'
}
response {
status 200
body([
"weather": value(regex("(SUNNY|WINDY|CLOUDY|RAINY)"))
])
}
I know Groovy DSL is able to generate a random value, Like the code above.
But the Groovy DSL just generate a static stub, and it will always return the same response as I requested.
How can I get a random weather without re-generate the stubs in this case?
You can't, that's because WireMock stub needs a concrete value on the response side. The only thing you could do is to reference the request from the response and then the request can have random input. In general, your tests shouldn't depend on random response.
I know is an old question but I found a workaround solution to achieve that using dynamic values from the given request, you can set a custom headers using $regex then use as output response.
Groovy
request {
method 'GET'
url """/v1/persons/${anyUuid()}"""
headers {
contentType('application/json')
header 'Authorization' : 'Mocked Return Data'
header 'nameMocked' : $(regex('[a-zA-Z0-9]{5, 30}'))
header 'dateMocked' : $(regex('(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[012])/([0-9]{4})'))
header 'typeMocked' : $(regex('CONSUMER|COMMERCIAL'))
}
}
response {
status 200
body(
"""
{
"name": "${fromRequest().header('nameMocked')}",
"date": "${fromRequest().header('dateMocked')}",
"type": "${fromRequest().header('typeMocked')}",
}
"""
)
headers {
contentType('application/json')
}
}
BaseClass
class PersonDto {
private UUID id;
private String name;
private LocalDate date;
private PersonType type;
}
#Slf4j
#RunWith(SpringRunner.class)
#ContextConfiguration(classes = JacksonAutoConfiguration.class)
public abstract class BaseTest {
#Autowired
private ObjectMapper objectMapper;
#Before
public void setup() throws Exception {
YourController yourController = spy(new YourController());
//normal business mocks
doAnswer((Answer<ResponseEntity>) invocation -> {
HttpServletRequest currentRequest = getCurrentRequest();
Map<String, String> map = Collections.list(currentRequest.getHeaderNames()).stream()
.filter(n -> n.endsWith("Mocked"))
.collect(Collectors.toMap(k -> k.replaceFirst("Mocked", ""), currentRequest::getHeader));
return ResponseEntity.ok(objectMapper.convertValue(map, PersonDto.class)); //Convert map to dto
}).when(YourController).getPerson(matches("([a-f0-9]{8}(-[a-f0-9]{4}){4}[a-f0-9]{8})"), eq("Mocked Return Data")); //This should match your request
RestAssuredMockMvc.standaloneSetup(yourController);
}
private HttpServletRequest getCurrentRequest() {
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
Assert.state(requestAttributes != null, "Could not find current request via RequestContextHolder");
Assert.isInstanceOf(ServletRequestAttributes.class, requestAttributes);
HttpServletRequest servletRequest = ((ServletRequestAttributes) requestAttributes).getRequest();
Assert.state(servletRequest != null, "Could not find current HttpServletRequest");
return servletRequest;
}
}
Consumer example
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)
#AutoConfigureStubRunner(workOffline = true, ids = "groupId:artifactId:+:stubs:8083")
#DirtiesContext
public class ConsumerContractAT {
#Test
public void callApiGetShouldReturnDynamicMockedData() {
Response response = RestAssured.given()
.header(HttpHeaders.AUTHORIZATION, "Mocked Return Data")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header("nameMocked", "Test")
.header("typeMocked", "CONSUMER")
.header("dobMocked", DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.of(2019, 10, 10)))
.when()
.get("/v1/persons/{tokeId}", UUID.randomUUID())
.then()
.statusCode(200)
.extract().response();
assertThat(response.jsonPath().getString("typeMocked")).isEqualTo("CONSUMER");
assertThat(response.jsonPath().getString("name")).isEqualTo("Test");
assertThat(response.jsonPath().getString("dob")).isEqualTo("10/10/2019");
response = RestAssured.given()
.header(HttpHeaders.AUTHORIZATION, "Mocked Return Data")
.header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
.header("nameMocked", "Test 2")
.header("typeMocked", "COMMERCIAL")
.header("dobMocked", DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.now()))
.when()
.get("/v1/persons/{tokeId}", UUID.randomUUID())
.then()
.statusCode(200)
.extract().response();
assertThat(response.jsonPath().getString("typeMocked")).isEqualTo("COMMERCIAL");
assertThat(response.jsonPath().getString("name")).isEqualTo("Test 2");
assertThat(response.jsonPath().getString("dob")).isEqualTo(DateTimeFormatter.ofPattern("dd/MM/yyyy").format(LocalDate.now()));
}
}
From the answer given for this question Can Retrofit with OKHttp use cache data when offline i was able to come up with this, but the code seems not to cache. What could i be doing wrong?
This my okhttp client
long SIZE_OF_CACHE = 10 * 1024 * 1024; // 10 MB
Cache cache = new Cache(getDirectory(), SIZE_OF_CACHE);
if (cache == null) {
Toast.makeText(AppController.getInstance().getApplicationContext(), "could n0t set cache", Toast.LENGTH_SHORT).show();
}
client = new OkHttpClient
.Builder()
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.cache(cache)
.build();
Add my network interceptor is as below:
private static final Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
#Override
public Response intercept(Chain chain) throws IOException {
Response originalResponse = chain.proceed(chain.request());
if (isConnected()) {
int maxAge = 60; // read from cache for 1 minute
return originalResponse.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
int maxStale = 60 * 60 * 24; // tolerate 1-day stale
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
}
};
Am adding to retrofit like this:
public static Retrofit getClient() {
createCacheForOkHTTP();
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.client(client)
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
//Add in my activity:
ApiInterface apiService =
ApiClient.getClient().create(ApiInterface.class);
Call<MovieResponse> call = apiService.getPopularMoviesDetails(ApiKey, page);
call.enqueue(new Callback<MovieResponse>() {
#Override
public void onResponse(Call<MovieResponse> call, Response<MovieResponse> response) {
progressBar.setVisibility(View.GONE);
mErrorView.setVisibility(View.GONE);
if (response.isSuccessful()) {
movies = response.body().getResults();
movieAdapter.setMovieList(movies);
mRecyclerView.setAdapter(movieAdapter);
} else {
Toast.makeText(getActivity(), "header" + response.headers() + "code" + response.code() + "errorbody" + response.errorBody() + "errorbody" + response.message(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<MovieResponse> call, Throwable t) {
progressBar.setVisibility(View.GONE);
// Log error here since request failed
Log.e(TAG, t.toString());
mErrorView.setVisibility(View.VISIBLE);
}
});
//interface
#GET("movie/popular")
Call<MovieResponse> getPopularMoviesDetails(#Query("api_key") String apiKey, #Query("page") int page);
You shouldn’t rewrite responses from the server to facilitate caching. It’s better to ask your server’s administrators to include cache headers when they serve responses. That way the cache works for all clients – not just OkHttp.
That said, you’re an adult and you’re entitled to take technical shortcuts to avoid talking to your server team.
First you need to change your code to use both a network interceptor and an application interceptor. Why two? Well, when you’re making requests into the cache the network interceptors haven’t run yet. And when you’re writing responses into the cache the application interceptors haven’t run yet.
Your application interceptor will rewrite your request headers to include this when you prefer the cache, and to permit the cache to serve stale responses:
Cache-Control: only-if-cached, max-stale=86400
Your network interceptor will rewrite your server’s response headers to include this so that all responses are cached for 24 hours:
Cache-Control: max-age=86400
Not sure if you already fix this. I found a great/short solution hope it helps.
I create a CacheControlInterceptor. This has 24 hours of cache, if there you are offline and your response is less than 24 hours old you will get the cache response.
public class CacheControlInterceptor implements Interceptor {
private static final String CACHE_CONTROL_HEADER = "Cache-Control";
private static final String MAX_AGE_HEADER_VALUE = "public, max-age=";
private static final String MAX_STALE_HEADER_VALUE = "public, only-if-cached, max-stale=";
// Specifies the maximum amount of time a resource will be considered fresh.
private static final int MAX_AGE = 60;
// Indicates that the client is willing to accept a response that has exceeded its expiration time.
private static final int MAX_STALE = 60 * 60 * 24; // 24 hours cache.
#Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
if (WatchItApplication.hasNetwork()) {
request = request.newBuilder()
.header(CACHE_CONTROL_HEADER, MAX_AGE_HEADER_VALUE + MAX_AGE).build();
} else {
request = request.newBuilder()
.header(CACHE_CONTROL_HEADER, MAX_STALE_HEADER_VALUE + MAX_STALE).build();
}
return chain.proceed(request);
}
}
On this method I create the OKHttpCliente . As you notice I am adding the CacheControlInterceptor and cache.
private OkHttpClient createDefaultOkHttpClient() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
return new OkHttpClient.Builder()
.retryOnConnectionFailure(true)
.connectTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT)
.readTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT)
.writeTimeout(TIMEOUT_MILLIS, TIMEOUT_UNIT)
.addNetworkInterceptor(new HeaderInterceptor())
.cache(new Cache(WatchItApplication.getInstance().getCacheDir(), 10 * 1024 * 1024))
.addInterceptor(new CacheControlInterceptor())
.addInterceptor(interceptor)
.build();
}
Finally retrofit:
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(createDefaultOkHttpClient())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
Let me know if that works.
I was able to resolve the issue.This is how i did it.
private static OkHttpClient getCacheClient(final Context context) {
Interceptor REWRITE_CACHE_CONTROL_INTERCEPTOR = new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
okhttp3.Response originalResponse = chain.proceed(chain.request());
if (isConnected()) {
// Internet available; read from cache for 0 day
// Why? Reduce server load, better UX
int maxAge = 0;
return originalResponse.newBuilder()
.header("Cache-Control", "public, max-age=" + maxAge)
.build();
} else {
// No internet; tolerate cached data for 1 week
int maxStale = 60 * 60 * 24 * 7;
return originalResponse.newBuilder()
.header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
.build();
}
}
};
File httpCacheDirectory = new File(context.getCacheDir(), "cachedir");
int size = 5 * 1024 * 1024;
Cache cache = new Cache(httpCacheDirectory, size);
return new OkHttpClient.Builder()
.addNetworkInterceptor(REWRITE_CACHE_CONTROL_INTERCEPTOR)
.cache(cache)
.build();
}
And usage:
public static Retrofit getClient(final Context context) {
if (retrofit == null) {
retrofit = new Retrofit.Builder()
.client(getCacheClient(context))
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
I'm writing a Nancy endpoint and I want to do something that I think should be really simple. I want to support returning the content in either json or xml but when html or any other type is requested to return a 406 Not supported. I can easily force either XML or JSON only, and I guess I could do and if (accept is html) return 406 but I would assume that there is some support for this in the content Negotiation support.
Can anybody shed any light?
Implement your own IResponseProcessor, Nancy will pick it up and hook in the engine.
public sealed class NoJsonOrXmlProcessor : IResponseProcessor
{
public ProcessorMatch CanProcess(MediaRange requestedMediaRange, dynamic model, NancyContext context)
{
if (requestedMediaRange.Matches("application/json") || requestedMediaRange.Matches("aaplication/xml"))
{
//pass on, so the real processors can handle
return new ProcessorMatch{ModelResult = MatchResult.NoMatch, RequestedContentTypeResult = MatchResult.NoMatch};
}
return new ProcessorMatch{ModelResult = MatchResult.ExactMatch, RequestedContentTypeResult = MatchResult.ExactMatch};
}
public Response Process(MediaRange requestedMediaRange, dynamic model, NancyContext context)
{
return new Response{StatusCode = HttpStatusCode.NotAcceptable};
}
public IEnumerable<Tuple<string, MediaRange>> ExtensionMappings { get; private set; }
}
We avoided the use of ResponseProcessor for the whole reason that the request was still being run all the way through our authentication layer, domain layer, etc. We wanted a way to quickly kill the request as soon as possible.
What we ended up doing was performing the check inside our own Boostrapper
public class Boostrapper : DefaultNancyBootstrapper
{
protected override void RequestStartup(TinyIoCContainer requestContainer, IPipelines pipelines, NancyContext context)
{
base.RequestStartup(requestContainer, pipelines, context);
pipelines.BeforeRequest += nancyContext =>
{
RequestHeaders headers = nancyContext.Request.Headers
if (!IsAcceptHeadersAllowed(headers.Accept))
{
return new Response() {StatusCode = HttpStatusCode.NotAcceptable};
}
return null;
}
}
private bool IsAcceptHeadersAllowed(IEnumerable<Tuple<string, decimal>> acceptTypes)
{
return acceptTypes.Any(tuple =>
{
var accept = new MediaRange(tuple.Item1);
return accept.Matches("application/json") || accept.Matches("application/xml");
});
}
}