Jetty HttpServletResponse can't be modified - firefox

we want to use jPlayer, an HTML5 audio player with firefox in order to play .ogg files. We noticed that there are issues with HTML5 audio and firefox considering the MEME attribute in the HTTP response. In this case, our content-type resembles "audio/ogg;charset=UTF-8". We think that removing the charset encoding might result in firefox interpreting the file correctly.
Hence, I tried the following in my spring implementation:
response.setContentType("audio/ogg");
response.setCharacterEncoding("");
The first line should not set an encoding. Nevertheless, it's already present before in the response object (recognized this while debugging). The weird thing is: the second line doesn't change anything, the character encoding is not modified. This behavior is totally contradictory to the API description.
Reference: it does not work as described in sample #2 of this post: Jetty Response with no Charset
I appreciate any ideas how-to fix the problem.
Cheers,
Chris

"Works for me..." (although you should set the char encoding to null rather than "")
I wrote some sample code (below) and ran it against 7.4.5
I get the right content type being sent through.
I'm not sure what's going wrong for you - perhaps you could post some code.
My best guess is that you're trying to set the content-type after having already sent content. Since the content type is a header, you need to set it before any of the body gets committed.
public class JettyServer
{
public static class OggServlet extends HttpServlet
{
protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException
{
File file = new File("src/main/ogg/file.ogg");
response.setContentType("audio/ogg");
response.setCharacterEncoding(null);
response.setContentLength((int) file.length());
FileInputStream in = new FileInputStream(file);
int by;
while ((by = in.read()) != -1)
{
response.getOutputStream().write(by);
}
}
}
public static void main(String[] args) throws Exception
{
Server server = new Server(8080);
ServletContextHandler handler = new ServletContextHandler();
handler.addServlet(OggServlet.class, "/audio");
server.setHandler(handler);
server.start();
}
}

I don't know if this will do anything different, but you could try bypassing the convenience method and calling setHeader method directly:
setHeader("Content-Type", "audio/ogg");
If you really are stumbling over some kind of bug in Jetty, it's worth a shot.

Related

Catching exception for server not available

I am new in spring boot and programming world .I am trying to post data on another server. I am using rest template to do that. I want to catch an exception when the server is not available .I am not sure how to do that .It would be helpful if anyone can just guide me where to look .I find so many examples but its getting more confusing.
Thanks in advance for your help.
You can use #Error Handler for this.You can use in your controller class to look around how this works when called.
#PostMapping("/hello")
public void hello(String msg)
{
RestTemplate restTemplate= new RestTemplate();
HttpEntity<String>reqEntity= new HttpEntity<>(msg);
restTemplate.postForEntity(" paste your server url here", reqEntity, String.class);
}
#ExceptionHandler(ConnectException.class)
#ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public void func()
{
System.out.println("I am not able to connect");
}
As you mentioned the server is not running so it will be handled by below mentioned function func on which #Exception handler is declared.You can read on #Exception handler.Certainly there are many different ways to do it.

Produce a JSONP with a ContainerRequestContext#abortWith

I have this Jersey2-based application, with a custom ContainerRequestFilter.
When the filter(ContainerRequestContext) method is called I want to do a check and, if needed, I want to be able to stop the request before entering the main logic of the application.
At the moment I'm using the ContainerRequestContext#abortWith method to block the call and return an "error" response to the client.
My application returns JSONP to the client, and if I block with abortWith the response is always a JSON.
Looking at the jersey sources I found
org.glassfish.jersey.server.internal.JsonWithPaddingInterceptor that is responsible of the JSONP serialization.
In the abortWith flow I see it fails to find the JSONP annotation, but I don't know where it search for it.
My method has it, in fact in the "normal" scenario (without the abortWith) I see correctly the JSONP format.
I found the solution.
The ContainerRequestFilter#filter method was something like
public void filter(final ContainerRequestContext crc) throws IOException {
if (/* logic */) {
CustomObject ret = new CustomObject();
ret.error = "error message";
crc.abortWith(Response.ok(ret)).build());
}
}
JsonWithPaddingInterceptor expected a response with a JSONP annotation so I retrieve them from the ResourceInfo#resourceMethod, with something like
public void filter(final ContainerRequestContext crc) throws IOException {
if (/* logic */) {
Annotation[] as = this.resourceInfo.getResourceMethod().getAnnotations();
CustomObject ret = new CustomObject();
ret.error = "error message";
crc.abortWith(Response.ok().entity(ret, as).build());
}
}
this way the annotation is correctly found

Cannot get Spring Boot to lazily resolve a multipart file

I have created a Spring Boot 2 demo application with the Spring Initializr and added the controller below:
#Controller
#RequestMapping("/demo")
public class UploadController {
private final static Logger LOG = LoggerFactory.getLogger(UploadController.class);
#PostMapping("/upload")
public ResponseEntity<String> uploadFile(
#RequestParam("metadata") MultipartFile metadata,
#RequestParam("payload") MultipartFile payload) throws IOException {
ObjectMapper mapper = new ObjectMapper();
Map metadataMap = mapper.readValue(metadata.getInputStream(), Map.class);
LOG.info("Received call to upload file {}", metadataMap.get("filename"));
LOG.info("File size: {}", payload.getBytes().length);
LOG.info("File {} successfully uploaded", metadataMap.get("filename"));
return ResponseEntity.ok().build();
}
}
I then added an application.yaml file containing this configuration:
spring:
servlet:
multipart:
max-file-size: 2000000MB
max-request-size: 2000000MB
resolve-lazily: true
My goal is to have the controller parse and log the metadata file before it starts reading the payload file, but the resolve-lazily setting seems to be ignored by Boot: the code inside the controller won't be executed until the whole body is read.
I use the command below to test the controller:
curl -F metadata=#metadata.json -F payload=#payload.bin http://localhost:8080/demo/upload
Is there anything wrong with my code/configuration? Am I getting the meaning of the setting right?
At present, if you want to avoid reading (and buffering) the whole body all at once, I think you will have to provide your own parser, as described in the answers here. What would be really interesting (but generally unnecessary) would be to do so in the form of a new MultipartResolver implementation.
There are two existing implementations documented for interface MultipartResolver, and both supply a function setResolveLazily(boolean) (standard), (commons). I have tried with both, and neither seem to allow for parsing or streaming multipart files or parameters independently.
Default is "false", resolving the multipart elements immediately, throwing corresponding exceptions at the time of the resolveMultipart(javax.servlet.http.HttpServletRequest) call. Switch this to "true" for lazy multipart parsing, throwing parse exceptions once the application attempts to obtain multipart files or parameters.
Despite what it says in the documentation, I have found that once you call resolveMultipart, the entire body is parsed and buffered before the call returns. I know this because I can watch the temp-files being created.
One note about "Is there anything wrong with my code"...
Answer: Yes, because by using #RequestParam you have indirectly asked Spring to resolve your parameters ahead of time, before your controller is ever called. What you should be able to do instead (if the documentation were correct) is request the parameters independently from inside your controller:
Configuration (application.properties):
spring.servlet.multipart.enabled = true
spring.servlet.multipart.resolve-lazily = true
Controller:
#PostMapping(path = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Void> postUpload(HttpServletRequest rawRequest) {
multipartResolver.setResolveLazily(true); // unclear why this is exists
MultipartHttpServletRequest request = multipartResolver.resolveMultipart(rawRequest);
String p1 = request.getParameter("first-parameter");
String p2 = request.getParameter("second-parameter");
System.out.println("first-parameter="+p1+", second-parameter"+p2);
multipartResolver.cleanupMultipart(request);
return new ResponseEntity<Void>(HttpStatus.ACCEPTED);
}
One useful aspect of resolve-lazily that I have discovered is that it allows you to write your own parser for some rest controllers while using the built-in parser for others (see my answer here). In other words, you don't have to use spring.servlet.multipart.enabled = false to get your parser to work. This is a minor breakthrough relative to other advice that I had seen previously.

Why does Jersey swallow my "Content-Encoding" header

Why does the following example swallow my HTTP-Header for "Content-Encoding" in the request. I am writing an application where I need to decode a custom encoding format. However, I can never get hold of the "Content-Encoding" header from the request. Neither in the actual resource nor in an ReaderInterceptor. In the response, this encoding header is not swallowed.
This behavior can be easily observed in the following (runnable) example:
public class Demo extends JerseyTest {
#Override
protected Application configure() {
enable(TestProperties.DUMP_ENTITY);
enable(TestProperties.LOG_TRAFFIC);
return new ResourceConfig(MyResource.class, MyInterceptor.class);
}
public static final String PATH = "path";
public static final String ENCODING = "my-encoding";
public static final String CUSTOM_HEADER = "X-Content-Encoding";
public static final String QUESTION = "question", ANSWER = "answer";
#Path(PATH)
public static class MyResource {
#POST
public Response handle(String value, #Context HttpHeaders httpHeaders) {
assertEquals(ENCODING, httpHeaders.getHeaderString(CUSTOM_HEADER));
// Here, the "Content-Encoding" header mysteriously disappeared.
assertEquals(ENCODING, httpHeaders.getHeaderString(HttpHeaders.CONTENT_ENCODING));
return Response
.ok(ANSWER)
.header(CUSTOM_HEADER, ENCODING)
.header(HttpHeaders.CONTENT_ENCODING, ENCODING)
.build();
}
}
public static class MyInterceptor implements ReaderInterceptor, WriterInterceptor {
#Override
public Object aroundReadFrom(ReaderInterceptorContext context)
throws IOException, WebApplicationException {
assertEquals(ENCODING, context.getHeaders().getFirst(CUSTOM_HEADER));
// Here, the "Content-Encoding" header mysteriously disappeared.
assertEquals(ENCODING, context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
return context.proceed();
}
#Override
public void aroundWriteTo(WriterInterceptorContext context)
throws IOException, WebApplicationException {
assertEquals(ENCODING, context.getHeaders().getFirst(CUSTOM_HEADER));
// Here, the "Content-Encoding" header can be found.
assertEquals(ENCODING, context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
context.proceed();
}
}
#Test
public void test() throws Exception {
Response response = target(PATH)
.request()
.header(CUSTOM_HEADER, ENCODING)
.header(HttpHeaders.CONTENT_ENCODING, ENCODING)
.post(Entity.text(QUESTION));
assertEquals(200, response.getStatus());
assertEquals(ENCODING, response.getHeaders().getFirst(CUSTOM_HEADER));
// Here, the "Content-Encoding" header can be found.
assertEquals(ENCODING, response.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING));
}
}
Is there some magic happening behind the curtains where Jersey tries to fix up my content encoding? (What it cannot since its a closed-source encoding which I must as a matter of fact resolve by querying another application on another server in the network.) I cannot even discover the "Content-Encoding" header in the request dump which is why I suspect Jersey to not send the header at all.
I could of course use some "X-Content-Encoding" header, this works as demonstrated in the example. But this solution is just dumb. I already searched the various CommonProperties, ServerProperties, ClientProperties constant pools but I did not find a configuration option.
The problem you see is because you are effectively overwriting the Content-Encoding header with the
.post(Entity.text(QUESTION));
call. The Entity.text(...) method produces entity with the content data Variant fields set to:
media type = "text/plain";
content language = null;
content encoding = null;
These null values of content encoding and language in turn erase any previously set Content-Encoding or Content-Language headers. To fix this, you need to specify the content encoding as part of your entity:
Response response = target(PATH)
.request()
.post(Entity.entity(QUESTION,
new Variant(MediaType.TEXT_PLAIN_TYPE, (String) null, "my-encoding")));
(I agree this behavior is somewhat confusing as it is not obvious. Perhaps we should fix Jersey to not override headers with null variant field values if set...)

Is it possible to get around the Cross-Origin limitation when calling the Google Places API Web service?

Is it possible enable the Google Placess API WebService to allow cross-origin requests from my domain so that I can access the service directly from the browser? I'v been experimenting with the API-keys by creating a Browser API key and then adding my domain to the referers list, but to no avail. Not sure if that is what the refeferer property is for anyway.
Is this limitation by design, or am I missing something here?
Google Places API WebService is the service that I want to use. Neither the Places Autocomplete or Places Search in the Places Library are suitable for my particular requirement.
Cheers
Stian
This is a client-side based limitation, so the short answer is: no.
However there are websites and services that try to surmount this problem by using scripts (loading them on the fly).
Have a look here and here (these articles are about generic cross-domain AJAX requests)
The Places-API is also available inside the Maps-Javascript-API, you don't need to struggle with cross-origins there.
Let me say its impossible to get around .I tried using java instead the code just works for http request(i used here is for graph.facebook.com):
public class search {
private static String readAll(Reader rd) throws IOException {
StringBuilder sb = new StringBuilder();
int cp;
while ((cp = rd.read()) != -1) {
sb.append((char) cp);
}
return sb.toString();
}
public static JSONObject readJsonFromUrl(String url) throws IOException, JSONException {
InputStream is = new URL(url).openStream();
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
String jsonText = readAll(rd);
JSONObject json = new JSONObject(jsonText);
return json;
} finally {
is.close();
}
}
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
System.getProperties().put("http.proxyHost", "172.16.0.2");
System.getProperties().put("http.proxyPort", "8080");
JSONObject json = readJsonFromUrl("http://maps.googleapis.com/maps/api/place/nearbysearch/json?key=AIzaSyBRlMLIdoTk-j4OZCucR47rVMLhMmvZVRw&type=hospital&location=12.8213125%2C80.0442&radius=500&_=1427359809583");
System.out.println(json.toString());
// System.out.println(json.get("about"));
// System.out.println("hello ");
}
}
If you replace the link with places api web search it will not work,the reason is that google does not give its services on HTTP domain,,, and my code only works on HTTP domain(not HTTPS)

Resources