Spring MVC gives HTTP 406 for application/octet-stream - spring-mvc

I am using Spring Web MVC and have written a controller that shall return binary data to a plugin in a web-page that show 3D content. This plugin uses STK files for it's models, so I have set-up my webapp to produce this kind of contents for *.stk URLs
The springDispatcherServlet is setup to handle *.stk requests in my web.xml
<servlet-mapping>
<servlet-name>springDispatcherServlet</servlet-name>
<url-pattern>*.stk</url-pattern>
</servlet-mapping>
My controller looks like this:
#Controller
#RequestMapping(value="/3dobject", produces="application/octet-stream")
public class Object3DController {
#Autowired
private DesignerService designerService;
#RequestMapping(value="/{article}.stk", method=RequestMethod.GET, headers="Accept: application/octet-stream")
public void getObject3DForArticle(HttpServletResponse response, #PathVariable String article) throws IOException {
response.setContentType("application/octet-stream");
Object3D object = designerService.get3DModelForArticleNumber(article, LanguageCode.NORWEGIAN);
byte[] content = object.getContent();
response.setContentLength(content.length);
IOUtils.write(content, response.getOutputStream());
}
}
When I try to access the data through a browser, I get the following error:
HTTP Status 406 - The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers.
I have deployed my app to a tomcat server on localhost.
Any ideas of what I must do to make the browser download the binary data?
PS! I changed from *.3do (3d object) to *.stk. With 3do it worked as expected, but the plugin fails with an error (which is hard to interpret), so I have to experiment in order to verify wether or not the URL extension matters...

The RequestMapping.produces() narrows the request and therefore is
only mapped if the Accept matches one of these media types
So you need to set the corresponding Accept header in the request from the plugin. This cannot be done by simply making an HTTP GET Request by typing in a URL into a browser. One plugin I find useful for Chrome is the Advanced REST Client. There are plenty of others that offer similar functionality. Alternatively try using cURL to make the request with the correct header.

Related

Disable access to a Servlet

I'm developing a WebApp using JavaEE and I use a servlet to test some stuff.
Currently, my WebApp is set as when I go to my local url localhost:8080/myApp/test , I can run my test Servlet.
My plan is to deploy my project to a Web and I want to disable the Servlet, but not delete it. I mean, if in the future I visit my remote server via URL www.myNewWeb.com/test , I would like it throws an error od do nothing.
How could I do that?
There are many possible options here:
Option 1
Remove the mapping (annotation #WebServlet or url mapping entry in web.xml). In this case, any attempt to call this servlet will end with an error generated by the JEE container of your choice. It will try to map the servlet to URL, will obviously fail and throw an exception
The obvious drawback of this method is that you need to change the deployment configuration and if you'll want to run the same artifact in another envrironment where this servlet should work you won't be able to do so.
Option 2
Create some kind of configuration, load this configuration along with your application.
In the doGet (just for the sake of example) method do something like this:
public void doGet(request, response) {
if(config.isTestServletEnabled()) { // this is where the data gets read from configuration that I've talked about before
// do your regular processing here
}
else {
// this will happen when the servlet should not be activated
// throw an exception, return HTTP error code of your choice, etc
}
}
This way doesn't have a drawback of the first method that I've explained above, however involves some code to be written.

ServletUriComponentsBuilder.fromRequest return http scheme instead of https

I have a web application composed by frontend code that invokes the same api implemented by two backend modules. This api returns a url in a JSON object. The backend modules are both written with spring mvc but in different versions.
The url-building is the same and it is something like this:
#GetMapping(path = "/app1/menu", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
public JsonObject getMenu(HttpServletRequest req) throws IOException {
JsonObject menu = new JsonObject();
menu.addProperty("href", ServletUriComponentsBuilder.fromRequest(req)
.replacePath(req.getContextPath())
.path("/index.html")
.toUriString());
return menu;
}
As you can see this code simply adds a constant to the incoming request and returns it.
The first app uses spring mvc 4 (4.3.5.RELEASE precisely).
The second module uses the 5.1.4.RELEASE version.
When all these apps are deployed on a load balanced server (2 tomcat instance with a load balancer upfront) and https the problem shows up.
Say that the request url is, for app1, something like this:
https://example.com/context/app1/menu
The app1 returns correctly
https://example.com/context/index.html
For the app2 the request issued by the frontend is
https://example.com/context/app2/menu
And the answer is
http://example.com/context/another_index.html
So it looses the https scheme
It seems that the ServletUriComponentsBuilder.fromRequest has changed behaviour?
I have taken a (quick I admit) look at the commits in the git repo but haven't
found anything ....

Customize Stream Path using http instead of rtmp

I currently have a Red5 application that uses a Custom Stream Path similar to the example shown on
Red5's wiki.
It works great when using the following rtmp stream:
rtmp://localhost:1935/streaming/videos/myVid.mp4
I need to be able to do the same thing with a http stream.
For example:
http://localhost:8080/streaming/videos/myVid.mp4
When I change the stream url from rtmp to http the CustomFilenameGenerator class is no longer being called.
Is it possible to have a Custom Stream Path while useing http? If so, is there a configuration or something that needs added/changed to make it work?
EDIT:
Just to be clear, currently I can only stream videos to my webpage that are located in the /red5Root/webApps/myApp/videos/ directory on my server machine.
I currently can use http://my.server.ip.address/myApp/videos/videoName.mp4 inside a video tag to play a video named "videoName.mp4" located in the videos directory on my server.
I want to be able to use http://my.server.ip.address/myApp/someUniqeIdOrName and have my Red5 CustomFilenameGenerator class then return the actual path (somewhere else in the file system on my server) of the video associated with the "someUniqeIdOrName" and play the video from that location.
To play a video by plain HTTP you just need a plain web server and embed it in a VIDEO tag.
If you want to play it by HLS (HTTP Live Streaming) or MPEG Dash, you need it segmented (packetised).
Live packetisation is done by Wowza Streaming Engine and is great to deliver live streams.
For existing videos you can also use pre-segmentation that can be done with FFMPEG. You can use the free Video Share VOD turnkey site solution to easily manage videos and generate segments on your site (if you have compatible hosting with FFMPEG and necessary codecs).
I wasn't able to find a way to get this to work with my CustomFilenameGenerator class but I found a different solution that gives me the same result.
I added a redirect servlet. In my web.xml add the following:
<servlet>
<servlet-name>fileServlet</servlet-name>
<servlet-class>com.my.package.stream.app.FileServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>fileServlet</servlet-name>
<url-pattern>/files/*</url-pattern>
</servlet-mapping>
Then I created a FileServlet class based off of the example here.
Once you get the filename from the request you can perform whatever logic based on the file name to set and return the actual location and name of the video/file you want in the response.
Example:
...
private void processRequest(HttpServletRequest request, HttpServletResponse response, boolean content) throws IOException {
// Get requested file by path info.
String requestedFile = request.getPathInfo();
// Check if file is actually supplied to the request URL.
if (requestedFile == null) {
// Do your thing if the file is not supplied to the request URL.
// Throw an exception, or send 404, or show default/warning page, or just ignore it.
response.sendError(HttpServletResponse.SC_NOT_FOUND);
return;
}
****** Insert logic here to set basePath and requestedFile to what you need ****
// URL-decode the file name (might contain spaces and on) and prepare file object.
File file = new File(basePath, URLDecoder.decode(requestedFile, "UTF-8"));
...
With the above servlet and similar FileServlet class I am able to play videos anywhere on my server by setting src="http://[myip]:8080/[myApp]/files/[uniqeFileNameOrId]"inside a video tag on my webpage.
NOTE: If you the file you are wanting to get back from your sever is not a video a simpler example of a FileServlet class is here.

Performing redirects in ServiceStack

I'm attempting to build a service in ServiceStack whose sole responsibility will be to interpret requests, and send a redirect response. Something like this:
[Route("/redirect/", "POST")
public class Redirect : IReturnVoid
{
public string Something { get; set; }
}
public class RedirectService : Service
{
public object Post(Redirect req)
{
// make some decisions about stuff
return new HttpResult(){ StatusCode = HttpStatusCode.Redirect, Headers = {{HttpHeaders.Location, "place"}}};
}
}
I did initial testing using fiddler, setting a content-type of application/json and creating an appropriate request body.This did exactly as expected: the service request gave a 302 response and redirected to the expected location.
I've also tested this by using a basic Html form post, with an action of http://myserviceuri/redirect/, which also works as expected and redirects appropriately.
However, i've hit an issue when attempting to use the SS c# client to call the same service. If I call the following code in an aspx code behind or an mvc controller
var client = new JsonServiceClient("uri);
client.post(new Redirect{Something = "something});
I get a 500 and the error message:
The remote certificate is invalid according to the validation procedure.
Which makes sense as it's a development server, with a self-cert. But I get the feeling that, as I can call the service successfully by other means, that this is a red herring.
Should I be using a different type of c# client to make the request, or setting any more custom headers, or something else? Am I fundamentally not understanding what i'm trying to do?
Please let me know if more info is needed. Thanks.
What's happening here is that the JsonServiceClient is happily following the redirect, doing more than what you've expected it to do.
I'll reference a related question and answer for posterity ( - hopefully you've resolved this issue a long time ago...).
POST to ServiceStack Service and retrieve Location Header
Essentially you'd use .net's WebRequest or the ServiceStack extensions mentioned in the answer to see the redirect and act as you see fit.

Filter is used as controller in Struts2

In struts2 why is a Filter is used as a controller instead of ActionServlet?
What is the advantage of using a Filter over ActionServlet?
As per Struts2 Budi Karnival struts2 book, There is one distinct advantage of using a filter over a servlet as a controller. With a filter you can conveniently choose to serve all the resources in your application, including static ones.
With a servlet, your controller only handles access to the dynamic part of the application. Note that the url-pattern element in the web.xml file in the previous application is
<servlet>
<servlet-name>Controller</servlet-name>
<servlet-class>...</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Controller</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
With such a setting, requests for static resources are not handled by the servlet controller, but by the container. You wouldn't want to handle static resources in your servlet controller because that would mean extra work.
A filter is different. A filter can opt to let through requests for static contents. To pass on a request, call the filterChain.doFilter method in the filter's doFilter method.
Consequently, employing a filter as the controller allows you to block all requests to the application, including request for static contents. You will then have the following setting in your deployment descriptor:
<filter>
<filter-name>filterDispatcher</filter-name>
<filter-class>...</filter-class>
</filter>
<filter-mapping>
<filter-name>filterDispatcher</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Advantage of this filter : One thing for sure, you can easily protect your static files from curious eyes.
The following code will send an error message if a user tries to view a JavaScript file:
public void doFilter(ServletRequest request, ServletResponse response,FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String uri = req.getRequestURI();
if (uri.indexOf("/css/") != -1 && req.getHeader("referer") == null) {
res.sendError(HttpServletResponse.SC_FORBIDDEN);
} else {
// handle this request
}
}
It will not protect your code from the most determined people, but users can no longer type in the URL of your static file to view it. By the same token, you can protect your images so that no one can link to them at your expense.
Another advantage :
The introduction of Interceptors in Struts2 framework.It not just reduce our coding effort,but helps us write any code which we would have used filters for coding and necessary change in the web.xml as opposed to Struts1.So now any code that fits better in Filter can now moved to interceptors( which is more controllable than filters), all configuration can be controlled in struts.xml file, no need to touch the web.xml file
We generally Use a Filter when we want to filter and/or modify requests based on specific conditions.
For S2 to work it needs to perform certain reprocessing and modification work in order for a successful execution of your request while on other hands we use Servlet when we want to control, preprocess and/or post-process requests.
For controlling request S2 use Servlet under the hood but being hidden away to make the overall application structure more clean and easy to use.
This is what we have for Filters in The Java EE 6 Tutorial.
A filter is an object that can transform the header and content (or both) of a request or response. Filters differ from web components in that filters usually do not themselves create a response. Instead, a filter provides functionality that can be “attached” to any kind of web resource. Consequently, a filter should not have any dependencies on a web resource for which it is acting as a filter; this way, it can be composed with more than one type of web resource.

Resources