I've some web page deployed at some server say:
http://myhost/some_secured_file.html
when I access this file within a browser it returns 401 asking me to authorize myself.
The problem is that I am trying to include this page inside some JSP page using the c:import tag.
The app server returns :
javax.servlet.jsp.JspException: Problem accessing the absolute URL "http://myhost/some_secured_file.html". java
.io.IOException: Server returned HTTP response code: 401 for URL: http://myhost/some_secured_file.html
How I can accomplish the include!?
Consider proxying the request through another jsp page or servlet. Then you let the proxy perform an authenticating request, e.g., using Apache HTTPClient, and have the contents of that response written to the page. Then you can simply import the url of your proxy on your jsp page.
Alright, consider the following pseudo code as clarification:
class Proxy extends HttpServlet {
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// Perform a new request to get contents from secured page
HttpClient client = new HttpClient();
Credentials credentials = new UsernamePasswordCredentials("user", "pass");
client.getState().setCredentials(authScope, credentials);
GetMethod method = new GetMethod("/secure_page.jsp");
client.executeMethod(client.getHostConfiguration();, method);
// write result to the outputstream
resp.getWriter().write( method.getResponseBodyAsString() );
}
}
What this servlet does is fetch the secured page for you. You need to hook this servlet up in your web descriptor. This is necessary to map e.g., /proxy.jsp request to it. What you then can do in your jsp page is something like <c:import value="proxy.jsp"/>.
Related
I am just a beginner in Java Web and I am exploring the pure Servlets and JSPs (with no frameworks). I am trying to build up a simple CRUD and I got stuck in an error that makes no sense at all (at least to me!).
Objective
I wanna build a simple CRUD with several Servlets containing the logics and database operations (controller) and JSPs to display the pages (views). I have already successfully build up a CustomerIndexServlet (route: /customers), which returns the list of records and a button to CustomerNewServlet (route: /customers/new) which SHOULD return a JSP with the form to create new records.
Issue
Calling CustomerNewServlet leads to a Page Not Found (404) and GlassFish prints the message PWC6117: File "null" not found in the console. By debugging the code, the error occurs when forwarding the request through RequestDispatcher. I don't understand! If I try to access the JSP directly (at http://localhost:8080/MyApp/customerForm.jsp), it returns OK (200). I even printed the path of JSP before forwarding to make sure it is the one expected!
#WebServlet(name = "NewCustomer", urlPatterns = {"/customers/new"})
public class NewCustomerServlet extends HttpServlet {
#Override
protected void doGet(
HttpServletRequest request,
HttpServletResponse response
) throws ServletException, IOException {
System.out.println(request.getContextPath());
if (request.getSession().getAttribute("login") == null)
/*error*/ request.getRequestDispatcher(request.getContextPath()).forward(request, response);
else
/*error*/ request.getRequestDispatcher(request.getContextPath() + "/customerForm").forward(request, response);
}
}
And in server's console it is displayed:
Info: /MyApp
Server: PWC6117: File "null" not found
What am I doing wrong? Does it have something to do with the file locations and directories?
I figured out what happen and how redirection and forward deal with URI's... I'm gonna share the knowledge I've acquired:
response.sendRedirect(URL)
When using the sendRedirect() method, you are requesting the client to submit a new request to the passed URL. When using an absolute path, you have to concatenate the request.getContextPath() prefix to your URL, if you wanna target a resource within your application.
request.getRequestDispatcher(URL).forward(...)
When dispatching the request to another URL, it already uses application context. So using request.getContextPath() + "/customerForm.jsp" as target URL will only look for a resource in /AppName/AppName/customerForm.jsp. Then, omitting the getContextPath() call is enough to make my code work as expected.
I know that HtmlUnit simulates a browser, while HttpClient doesn't.
In HtmlUnit, when a page is loaded and there is a JavaScript inside, will the script be executed? If the script sets a cookie, will the cookie set in HtmlUnit's browser and accessible from Java code?
Is there anything that can be done using HttpClient, but not using HtmlUnit? In HtmlUnit, can we start with a POST request and modify any part of HTTP request including method, URI, HTTP version, headers, and body?
What are the advantages of HttpClient over HtmlUnit?
HttpClient is a library at a lower-level, to send HTTP requests and retrieve responses.
HtmlUnit is at a higher level, and internally uses HttpClient to make HTTP requests, but also handles JavaScript (through Rhino and internal DOM implementation), XPath (through Xalan), CSS (through CSSParser), malformed HTML (through NekoHtml), WebSockets (through Jetty), etc.
You can modify the outgoing requests and response in HtmlUnit by something like:
new WebConnectionWrapper(webClient) {
public WebResponse getResponse(WebRequest request) throws IOException {
WebResponse response = super.getResponse(request);
if (request.getUrl().toExternalForm().contains("my_url")) {
String content = response.getContentAsString("UTF-8");
//change content
WebResponseData data = new WebResponseData(content.getBytes("UTF-8"),
response.getStatusCode(), response.getStatusMessage(), response.getResponseHeaders());
response = new WebResponse(data, request, response.getLoadTime());
}
return response;
}
};
as hinted here.
You can change the used HttpClient in HtmlUnit by overriding HttpWebConnection.createHttpClient().
You can make POST request by:
WebRequest webRequest = new WebRequest(url, HttpMethod.POST);
HtmlPage page = webClient.getPage(webRequest);
So Basically I have:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.getRequestDispatcher("/zips/packet.html").forward(request, response);
return;
}
As you can you can see when a request is made for this servlet, It responds with packet.html file. To be precise, inside my packet.html I have a video element with src="" which I need to fill it by users requested url.
Question: How do I send a little extra data saying video source to the client, So in my client side it could change the video source from src="" to src="actual video source"
I TRIED:
String video_source = "/zips/video.mp4";
response.getWriter().append(video_source);
request.getRequestDispatcher("/zips/packet.html").forward(request, response);
With this method I can see my packet.html being received in my front-end But I can't find the video_source. FYI: don't know how to receive the video_source.
Well, To satasify your demand you can follow many apporoaches. One approach that I would suggest would put into consideration whatever you've already started
As Below
Step 1. Forward your request and response objects into packet.jsp,instead of into packet.html
Step 2. inside packet.jsp grab the input from user and send it with
the request object from packet.jsp
Step 3. Write a servlet class that process the request object from
packet.jsp and send the video as mulitpart file with the response.
Moreover, Do some research on how to use jsp's and servlets
The second approach would be to write client side javascript code that send ajax request to grab the video in a second call. For this you might even consider some client side frameworks and libraries(like jquery, angular, etc) that ease your work.
You could do the following:
Pass that additional information via request attribute (request.setAttribute())
Use some dynamic handler (like a servlet or JSP) to serve /zips/handler.html
Use request.getAttribute() in that handler.
So:
in your initial servlet, put
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setAttribute("real_source", /some real source/);
request.getRequestDispatcher("/zips/packet.html").forward(request, response);
return;
}
In your /zips/packet.html you just use request.getAttribute("real_source") to generate the html attribute you need.
I am having issue with Redirect in Java servlet. I want to use Status 401 ( Not authenticated ) instead of 302.
Let say that I have a protected resource with Url is "/protected". This Url mapped to ProtectedServlet. In doGet of ProtectedServlet, I will check whether the request is authenticated OR not, If not, the servlet will redirect the request to Login page. Here is my code:
ProtectedServlet.java
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
boolean isAuth = this.checkAuth();
if (isAuth == false) {
// WAY1
resp.setStatus(401);
resp.sendRedirect(resp.encodeRedirectURL(loginUrl));
// WAY2
resp.setStatus(401);
resp.setHeader("Location", resp.encodeRedirectURL(loginUrl));
}
}
RESULT
If I used "WAY1", when I request "/protected", I will see LOGIN page
but return Status is 302, NOT 401 as I expected.
If WAY2 used: When I request "/protected", I WILL NOT see Login
page. I see EMPTY page return with NO status.
Anyone know what I am wrong? Thanks.
The HTTP protocol is well defined. The client sends an HTTP request and the server sends them back an HTTP response.
The HTTP response can only have one status code. You can see your options here. In other words, you can't do a redirect by sending a 401. You could put a Location header in your 401 response but you would have to tell your client what to do with it because it isn't standard.
Instead of redirecting, if your user is not authenticated return a 401 and render the same Login page HTML, ie. do a RequestDispatcher#forward(..) to the login jsp.
I am trying to implement a very basic functionality of uploading images from Android,iPhone and web clients to the google app engine. I did an initial version of the implementation thanks to this blog:
However there always seems to be a 2 step process to uploading an image:
Get the initial upload URL to POST to using the createUploadUrl(). I am attaching the fragment of code which I use :
public class CreateUploadUrl extends HttpServlet {
#Override
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
String uploadURL = blobstoreService.createUploadUrl("/image/uploadImage");
resp.setContentType("text/plain");
resp.getWriter().println(uploadURL);
}
}
POST the image using the URL which you just "got"
public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
BlobKey blobKey = ParameterExtractor.getBlobParameter(req, "blob-key", blobstoreService);
if (blobKey == null) {
log.info("blob Id is null. POST failed");
} else {
log.info("ze business logic");
}
}
My question is if it is possible to do it in one step since right now all clients need to do a http GET to get the upload URL and then a http POST to POST the image.
Is it not possible to just do one Http POST with a predefined URL.
Thanks
Rajat
This is possible, with limitations. You can bypass the UploadUrl mechanism by creating blobs directly in your servlet using the (currently experimental) createNewBlobFile API. In your mobile app(s) create an HTTP request encoded as multipart/form-data, and teach your servlet how to decode such a thing (consult e.g. How to upload files in JSP/Servlet?). Be aware that HTTP requests are limited to 32MB; with form encoding the amount of binary data you can upload will be less than that.
Sure you can do it with single POST. For example you have user that have an id. This user select image and you send in POST image data and user data on client side.
On server side (GAE) you have url for image uploding (your_host/imageUpload) and server or Spring controller that read data from request and write it to Blobstore.