Dear domino cognoscenti,
I've just written a simple xAgent using an xpage which works for GET requests but when I submit a POST request I get an Error 500 HTTP Web Server: Command Not Handled Exception with the following detail CLFAD0384E: Page instance not found. The $$viewid ID was not present in a POST request (thanks Per for the hint).
Here's the code. What am I doing wrong? Do xpages not handle POST requests by default? Do I have to enable this or something?
Thanks very much for your time! 😊
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
<xp:this.resources>
</xp:this.resources>
<xp:this.afterRenderResponse>
<![CDATA[#{javascript:
var exCon = facesContext.getExternalContext();
var requestMethod = exCon.getRequest().getMethod();
var response = exCon.getResponse();
var writer = facesContext.getResponseWriter();
response.setContentType("text/plain");
response.setHeader("Cache-Control", "no-cache");
writer.write(requestMethod);
writer.endDocument();
}]]>
</xp:this.afterRenderResponse>
</xp:view>
Edited 16 October 2022
I've tried the following:
Added viewState="nostate" to xp:view. (thanks Mark for that)
Had no code in the afterRenderResponse other than logging - still
get the same problem.
Used code in the beforeRenderResponse - same problem.
Tried the restService - same.
The only thing that appears to fix it is:
Introduce a field called $$viewid and set this to the value '!!' or '!0!' or similar.
Use the FormData Web API on the browser to build the request body.
Send it as Content-Type:multipart/form-data.
Sending it as plain text, application/json etc doesn't work. For some reason the xpage won't accept other encoding types.
Any ideas anyone?
I haven't tested it, but it might help to add viewState="nostate" to the xp:view. That's a good idea for XAgents anyway. See here for an explanation.
The issue is with CSRF protection as detailed in this blog post. When creating an xpage, in xsp.properties, the setting xsp.csrf.protection=true needs to be set to false (annoyingly it's not part of the UI, you have to go to the source tab).
The explainer from the blog post is as follows.
If you look in a new NSF the xsp.properties contains a setting
xsp.csrf.protection=true .
This enables a built-in framework for CSRF protection 😊 and was very
easily retrofitted to our existing NSFs.
When this feature is enabled every XPage contains a token such as
<input type=”hidden” name=”$$viewid” id=”view:_id1__VUID”
value=”!1to6ah3iyy1uc2gquai14d7ik!”>
If the returned XPage does not
have this same token then an error is generated. The error will be
CLFAD0253E: Cannot find a page instance corresponding to the ID:
$$viewid=!aaaaaaaaaa!. It may have expired. Try loading the web page
Setting this to false prevents this from occuring and the code works as expected (however see here for the multipart/form-data) Obviously there are risks so this isn't ideal but it's the cause of the problem seen. Setting this from true to false stops this from occurring.
Thanks to Sean Cull at Focul for pointing this out. If following this path, we'd have to code our own CSRF token handler.
Thanks to everyone else who contributed above. I appreciate your time.
I do this a lot - though using Java beans. Let me show you:
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false" viewState="nostate">
<xp:this.beforeRenderResponse><![CDATA[#{javascript:ServiceController.process()}]]></xp:this.beforeRenderResponse>
</xp:view>
Not sure if this is an important difference but I use the "beforeRenderResponse" event...
In my Controller bean I have this public method:
public void process() {
String method = null;
try {
setLanguage(null);
method = Util.getHttpRequest().getMethod();
if ("POST".equalsIgnoreCase(method)) {
processPostRequest();
} else {
processGetRequest();
}
} catch (Exception e) {
// Make sure any uncaught errors are logged and a proper response is returned
sendResponse(new Error(e.getLocalizedMessage()));
}
}
The "Util" class has these helpers:
public static ExternalContext getExternalContext() {
return getFacesContext().getExternalContext();
}
public static XSPContext getXspContext() {
return XSPContext.getXSPContext(getFacesContext());
}
public static HttpServletRequest getHttpRequest() {
return (HttpServletRequest) getExternalContext().getRequest();
}
In the processPostRequest() method I get the data from the request through the request reader. In my sample I use Json to parse the contents to JSON like this:
List<PostObject> postList = new ArrayList<PostObject>();
JsonJavaFactory factory = JsonJavaFactory.instanceEx;
JsonJavaObject jsonObjs = (JsonJavaObject) JsonParser.fromJson(factory, Util.getHttpRequest().getReader());
As you send plain text you would just read the data from the reader.
HTH - happy coding ;-)
/John
Related
I have a project setup in KIE Workbench, version 6.5.0 and a KIE execution server 6.5.0 running, all on the same local Wildfly 10. It is working fine.
I have a simple rule that is being executed in a stateless KieSession, no process or whatsoever. I expect the rule to validate basic information and to add information about the fired validations to a global variable. In the example I am testing I just modify a global variable to see if it works, but for some reason I never get a result from the service, which I expect to have at least something.
This is the JAXB request I send:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<batch-execution lookup="kieSessionStateless">
<insert disconnected="false" entry-point="DEFAULT" return-object="false" out-identifier="myorganization.myproject.bom.MyObject">
<object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="myObject">
<myDescription>description</myDescription>
<myID>0</myID>
</object>
</insert>
<set-global out-identifier="globalList" identifier="globalList">
<object xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="jaxbListWrapper">
<type>LIST</type>
</object>
</set-global>
<get-objects out-identifier="globalList"/>
<fire-all-rules max="-1"/>
</batch-execution>
The rule that is executed is quite simple:
rule "MY FIRST RULE"
when
myorganization.myproject.bom.MyObject( myID == 0 )
then
myorganization.myproject.bom.GlobalResponses globalResponses = new myorganization.myproject.bom.GlobalResponses();
globalResponses.setRuleName("MY FIRST RULE");
globalResponses.setRuleResponse("MY ID IS 0");
globalList.add(globalResponses);
System.out.println("MY ID IS 0");
end
And in the Wildfly console I see the line printed without any additional information (like a stacktrace of an error), so I conclude all is working well:
13:04:36,315 INFO [stdout] (default task-39) MY ID IS 0
But I always get the same response: it indicates that the "process" has terminated correctly (so it seems at first sight) and therefore I am expecting that Result has something (an empty xml response, an xml response with some data in it, ...):
System.out.println("Message: "+response.getMsg());
System.out.println("Result: "+response.getResult());
System.out.println("Type: "+response.getType());
Message: Container KieContainer successfully called.
Result: null
Type: SUCCESS
Response: ServiceResponse[SUCCESS, msg='Container KieContainer successfully called.']
The client is called with KieServicesClient:
KieServicesConfiguration config = KieServicesFactory.
newRestConfiguration(urlKieServer,
name,
password);
config.setMarshallingFormat(MarshallingFormat.JAXB);
KieServicesClient client = KieServicesFactory.newKieServicesClient(config);
JAXBContext jaxbContext = DroolsJaxbHelperProviderImpl.createDroolsJaxbContext(classNames, null);
Marshaller marshaller = jaxbContext.createMarshaller();
StringWriter xml = new StringWriter();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(command, System.out);
marshaller.marshal(command, xml);
ServiceResponse<String> response = client.executeCommands("instances/"+containerName, xml.toString());
I am missing something but I really do not know what.
All the related projects are on GitHub. Since I cannot post more than two links, I will add the direct links in a comment.
This question is also on:
Drools User group
I was able to complete the life cycle and send a valid request and obtain a valid answer. Part of my problem was the code used to construct the XML. The best way to construct a valid JAXB request is by using the API provided by KIE, an example can be found
here.
Anyway interested in establishing connection to a KIE Server 6.5.0 with a generic client project can consult the code on my GitHub.
I am using liferay 6.1.1.ga2 community edition.
I have a custom portlet in which I have insurance application form.
Now using postLogin(login hook) I am able to redirect to this insurance application page once he logs in .
public void run(HttpServletRequest request, HttpServletResponse response)
throws ActionException {
long usersId = PortalUtil.getUserId(request);
User u=UserLocalServiceUtil.getUser(usersId);
Role role = RoleLocalServiceUtil.getRole(u.getCompanyId(),
"Not Insured");
if(!RoleLocalServiceUtil.hasUserRole(u.getUserId(),role.getRoleId())){
response.sendRedirect("/group/secure/insuranceForm");
}
}
This works fine for me. But suppose if user tries to change the url(entered applications other url) and hits, it redirects to that url which should not.
Means I want to stay user on insurance application until he completes
it. Same feature that we see in password screen, reminder
*question* screen or in agree *page* when user login first time.
Same thing I want to perform for my insurance application page. How can I do this? I am using liferay 6.1.1.
I have tried with PortalRequestProcessor.java file made a ext plugin for that.
As we have a protected String processPath(HttpServletRequest request, HttpServletResponse response){} method, I also applied my condition and tried to to return static string which is nothing but my insurance form page in this way.
if (!RoleLocalServiceUtil.hasUserRole(user.getUserId(),roles.getRoleId()) {
return _PATH_INSURANCE_FORM;
}
.....
//static variables declaration
private static final String _PATH_PORTAL_LOGOUT = "/portal/logout";
private static final String _PATH_INSURANCE_FORM =
"/group/app/insurance?insurances=insuranceform";
But it shows error as
Content Encoding Error
The page you are trying to view cannot be shown because it uses an invalid or unsupported form of compression.
and at the log level it shows :
ERROR [http-bio-8080-exec-9][RequestProcessor:676] Invalid path was requested /group/app/insurance?insurances=insuranceform
ERROR [http-bio-8080-exec-9][PortalRequestProcessor:550] User ID 16040
And at browser console it's showing "NetworkError: 404 Not Found - http://189.0.25.23:8080/group/app/insurance?insurances=insuranceform"
But if I replace return path with existing path like (e.g :_PATH_PORTAL_LOGOUT) then it logouts user properly.
I am also checking at LoginPostAction(login-hook) same condition and redirecting to insurance page.
Is these static string variables declaration place is at different place?
So can anybody tell me how can I overcome from this problem ?
Thanks,
Related question: Web API action parameter is intermittently null and http://social.msdn.microsoft.com/Forums/vstudio/en-US/25753b53-95b3-4252-b034-7e086341ad20/web-api-action-parameter-is-intermittently-null
Hi!
I'm creating a ActionFilterAttribute in ASP.Net MVC WebAPI 4 so I can apply the attribute in action methods at the controller that we need validation of a token before execute it as the following code:
public class TokenValidationAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext filterContext)
{
//Tried this way
var result = string.Empty;
filterContext.Request.Content.ReadAsStringAsync().ContinueWith((r)=> content = r.Result);
//And this
var result = filterContext.Request.Content.ReadAsStringAsync().Result;
//And this
var bytes = await request.Content.ReadAsByteArrayAsync().Result;
var str = System.Text.Encoding.UTF8.GetString(bytes);
//omit the other code that use this string below here for simplicity
}
}
I'm trying to read the content as string. Tried the 3 ways as stated in this code, and all of them return empty. I know that in WebApi I can read only once the body content of the request, so I'm commenting everything else in the code, and trying to get it run to see if I'm getting a result. The point is, the client and even the Fiddler, reports the 315 of the content length of the request. The same size is getting on the server content header as well but, when we try read the content, it is empty.
If I remove the attribute and make the same request, the controller is called well, and the deserialization of Json happens flawless. If I put the attribute, all I get is a empty string from the content. It happens ALWAYS. Not intermittent as the related questions state.
What am I doing wrong? Keep in mind that I'm using ActionFilter instead of DelegatingHandler because only selected actions requires the token validation prior to execution.
Thanks for help! I really appreciate it.
Regards...
Gutemberg
By default the buffer policy for Web Host(IIS) scenarios is that the incoming request's stream is always buffered. You can take a look at System.Web.Http.WebHost.WebHostBufferPolicySelector. Now as you have figured, Web Api's formatters will consume the stream and will not try to rewind it back. This is on purpose because one could change the buffer policy to make the incoming request's stream to be non-buffered in which case the rewinding would fail.
So in your case, since you know that the request is going to be always buffered, you could get hold of the incoming stream like below and rewind it.
Stream reqStream = await request.Content.ReadAsStreamAsync();
if(reqStream.CanSeek)
{
reqStream.Position = 0;
}
//now try to read the content as string
string data = await request.Content.ReadAsStringAsync();
I have a Jersey POST REST service that both produces and consumes MediaType.APPLICATION_XML.
I also have a ServletFilter that does some authentication:
if (request instanceof HttpServletRequest) {
//read headers
//authenticate
filterChain.doFilter(request, response);
...
Without the filter in the picture, my REST api works perfectly.
With the filter, I do see the response XML in Firebug but with a 400 Status code:
javax.xml.bind.UnmarshalException
- with linked exception:
[org.xml.sax.SAXParseException: Premature end of file.]
The posts I read alluded to the filter altering the response, but I really don't know what to do to fix this.
Please help!
I used the ContainerRequestFilter instead of a javax.servlet.Filter and things work well.
My Scenario:
I am using Monotouch for iOS to create an iPhone app. I am calling ASP.NEt MVC 4 Web API based http services to login/log off. For Login, i use the POST webmethod and all's well. For Logoff, i am calling the Delete web method. I want to pass JSON data (serialized complex data) to the Delete call. If i pass simple data like a single string parameter as part of the URL itself, then all's well i.e. Delete does work! In order to pass the complex Json Data, here's my call (i have adjusted code to make it simple by showing just one parameter - UserName being sent via JSON):
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://localhost/module/api/session/");
req.ContentType = "application/json";
req.CookieContainer = jar;
req.Method = "Delete";
using (var streamWrite = new StreamWriter(req.GetRequestStream()))
{
string jSON = "{\"UserName\":\"" + "someone" + "\"}";
streamWrite.Write(jSON);
streamWrite.Close();
}
HttpWebResponse res = (HttpWebResponse)req.GetResponse();
on the server, the Delete method looks has this definition:
public void Delete(Credentials user)
where Credentials is a complex type.
Now, here's the issue!
The above code, gets into the Delete method on the server as soon as it hits:
req.GetRequestStream()
And hence the parameter sent to the Delete method ends up being null
And here's the weird part:
If i use the exact same code using a test VS 2010 windows application, even the above code works...i.e it does not call Delete until req.GetResponse() is called! And in this scenario, the parameter to the Delete method is a valid object!
QUESTION
Any ideas or Is this a bug with Monotouch, if so, any workaround?
NOTE:
if i change the Delete definition to public void Delete(string userName)
and instead of json, if i pass the parameter as part of the url itself, all's well. But like i said this is just a simplified example to illustrate my issue. Any help is appreciated!!!
This seems to be ill-defined. See this question for more details: Is an entity body allowed for an HTTP DELETE request?
In general MonoTouch (based on Mono) will try to be feature/bug compatible with the Microsoft .NET framework to ease code portability between platforms.
IOW if MS.NET ignores the body of a DELETE method then so will MonoTouch. If the behaviour differs then a bug report should be filled at http://bugzilla.xamarin.com