I am working on below scenario since last two days,
I have developed a java filter that check whether request is multipart type,
If it is, I want to restrict .php file getting uploaded.
In servlet filter I successfully retrieved type of file, if it's valid one, i have forwarded that request to proceed.
Now my business logic that was working exactly fine without filter is now failed to upload.
My project is using Spring framework.
At business logic, I'm using MultipartRequest(class of spring) as casting in.
Invoking request.getFileNames() which is returning nothing after involving filter.
In filter, I have wrapped request after validating file extensions as follows:
All form fields are set in parameter map that will be passed with request.
And File type field is set as attribute in request object.
Would you guys please help?
Thanks,
Namrata Shah
In doFilter(),
I have checked whether received request is instance of HttpServletRequest. If yes, then it'll be parsed if it's a multipart req using below code:
parseRequest():
{
List<FileItem> multipartItems = null;
try
{ multipartItems = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request);
}
catch (FileUploadException e)
{
throw new ServletException("Cannot parse multipart request: " + e.getMessage());
}
Map<String, String[]> parameterMap = new HashMap<String, String[]>();
for (FileItem multipartItem : multipartItems)
{
if (multipartItem.isFormField())
processFormField(multipartItem, parameterMap);
else
processFileField(multipartItem, request);
}
return wrapRequest(request, parameterMap);
}
Code for processFileField():
request.setAttribute(fileField.getFieldName(), fileField);
then, I wrap request as follows:
private static HttpServletRequest wrapRequest(
HttpServletRequest request, final Map<String, String[]> parameterMap)
{
return new HttpServletRequestWrapper(request)
{
#Override
public Map<String, String[]> getParameterMap()
{
return parameterMap;
}
public String[] getParameterValues(String name)
{
return parameterMap.get(name);
}
public String getParameter(String name)
{
String[] params = getParameterValues(name);
return params != null && params.length > 0 ? params[0] : null;
}
public Enumeration<String> getParameterNames()
{
return Collections.enumeration(parameterMap.keySet());
}
};
}
Code for processFormField():
String name = formField.getFieldName(),value = formField.getString();
String[] values = parameterMap.get(name);
if (values == null)
{
parameterMap.put(name, new String[]{value});
}
else
{
int length = values.length;
String[] newValues = new String[length + 1];
System.arraycopy(values, 0, newValues, 0, length);
newValues[length] = value;
parameterMap.put(name, newValues);
}
Related
I need to know how Spring boot maps the request parameters in the URL to a POJO at run time.
Here is an example URL with parameters
http://localhost:8080/api/public/properties?serviceType.in=SALE&title.contains=some text&price.greaterOrEqualThan=500&price.lessOrEqualThan=50000&propertyType.in=HOUSE&locationId.in=1,2&landSize.greaterOrEqualThan=100&landSize.lessOrEqualThan=1000&bedrooms.greaterOrEqualThan=2&bedrooms.lessOrEqualThan=5&bathrooms.greaterOrEqualThan=1&bathrooms.lessOrEqualThan=3&ageType.in=BRAND_NEW
I have a number of Criteria classes that all extends PropertyCriteria class. To give an example, if the request contains no parameters, I want the controller to use the PropertyCriteria. If the request contains a bedrooms parameter, I want the controller to use the HousePropertyCriteria and so on. See controller method example below.
#GetMapping("/public/properties")
public ResponseEntity<List<Property>>
getAllPropertiesNested(HttpServletRequest request) {
if (condition1 == true) {
EntityOnePropertyCriteria c1 = new EntityOnePropertyCriteria();
//populate c1 using request object
} else {
EntityTwoPropertyCriteria c2 = new EntityTwoPropertyCriteria();
//populate c2 using request object
}
}
Two ways of doing this manually:
1) I wonder if in your project you have access to HttpServletRequest object. If that is the case, you can use the method request.getParameter(nameParam) to populate the object that you need.
2) Use beanutils library and using the method
BeanUtils.copyProperties(dest, source)
Using "#RequestParam Map source" in your controller and replacing the dest object you want fill
I found the answer on this link.
public static void applyMapOntoInstance(Object instance, Map properties) {
if (properties != null && !properties.isEmpty()) {
BeanWrapper beanWrapper = PropertyAccessorFactory.forBeanPropertyAccess(instance);
beanWrapper.setAutoGrowNestedPaths(true);
for (Iterator<?> iterator = properties.entrySet().iterator(); iterator.hasNext();) {
Map.Entry<String, ?> entry = (Map.Entry<String, ?>) iterator.next();
String propertyName = entry.getKey();
if (beanWrapper.isWritableProperty(propertyName)) {
beanWrapper.setPropertyValue(propertyName, entry.getValue());
}
}
}
}
My controller method now looks like:
#GetMapping("/public/properties")
#Timed
public ResponseEntity<List<Property>> getAllPropertiesNested(HttpServletRequest request) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException {
HttpHeaders headers = null;
if (requestContains("bedrooms", request)) {
HousePropertyCriteria housePropertyCriteria = new HousePropertyCriteria();
applyMapOntoInstance(housePropertyCriteria, request.getParameterMap());
Page<HouseProperty> page = housePropertyQueryService.findByCriteriaNested(housePropertyCriteria, pageable);
headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/public/properties");
return new ResponseEntity(page.getContent(), headers, HttpStatus.OK);
} else {
Page<Property> page = propertyQueryService.findByCriteriaNested(criteria, pageable);
headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/public/properties");
return new ResponseEntity(page.getContent(), headers, HttpStatus.OK);
}
}
I have implemented filter and I have called getEntityStream of ContainerRequestContext and set the exact value back by using setEntitystream. If i use this filter then #FormParameter data becomes null and if i don't use filter then everything will be fine (as I am not calling getEntityStream) and i have to use filter to capture request data.
Note: I am getting form params from MultivaluedMap formParams but not from #FormParameter.
Environment :- Rest Easy API with Jboss Wildfly 8 server.
#Provider
#Priority(Priorities.LOGGING)
public class CustomLoggingFilter implements ContainerRequestFilter, ContainerResponseFilter{
final static Logger log = Logger.getLogger(CustomLoggingFilter.class);
#Context
private ResourceInfo resourceInfo;
#Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
MDC.put("start-time", String.valueOf(System.currentTimeMillis()));
String entityParameter = readEntityStream(requestContext);
log.info("Entity Parameter :"+entityParameter);
}
private String readEntityStream(ContainerRequestContext requestContext){
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
final InputStream inputStream = requestContext.getEntityStream();
final StringBuilder builder = new StringBuilder();
int read=0;
final byte[] data = new byte[4096];
try {
while ((read = inputStream.read(data)) != -1) {
outStream.write(data, 0, read);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] requestEntity = outStream.toByteArray();
if (requestEntity.length == 0) {
builder.append("");
} else {
builder.append(new String(requestEntity));
}
requestContext.setEntityStream(new ByteArrayInputStream(requestEntity) );
return builder.toString();
}
return null;
}
}
class customResource
{
//// This code is not working
#POST
#Path("voiceCallBack")
#ApiOperation(value = "Voice call back from Twilio")
public void voiceCallback(#FormParam("param") String param)
{
log.info("param:" + param);
}
// This code is working
#POST
#Path("voiceCallBackMap")
#ApiOperation(value = "Voice call back from Twilio")
public void voiceCallbackMap(final MultivaluedMap<String, String> formParams)
{
String param = formParams.getFirst("param");
}
}
please suggest me solution & Thanks in Advance.
I found during run time that instance of the entity stream (from http request) is of type org.apache.catalina.connector.CoyoteInputStream (I am using jboss-as-7.1.1.Final). But we are setting entity stream with the instance of java.io.ByteArrayInputStream. So Resteasy is unable to bind individual formparmeters.
There are two solutions for this you can use any one of them :
Use this approach How to read JBoss Resteasy's servlet request twice while maintaing #FormParam binding?
Get form parameters like this:
#POST
#Path("voiceCallBackMap")
#ApiOperation(value = "Voice call back from Twilio")
public void voiceCallbackMap(final MultivaluedMap<String, String> formParams)
{
String param = formParams.getFirst("param");
}
in xpages I can use:
var protocol = context.getUrl().getScheme() + "://";
var url:XSPUrl = new XSPUrl(database.getHttpURL());
var host = url.getHost();
...
to build urls to documents/files in documents
How should I build the URL's equivalent in Java?
I build URL's in Java all the time.
Here are some RANDOM code snippets that I use. This is not a single class, just random snippets that should help you get started at least.
FacesContext facesContext = FacesContext.getCurrentInstance();
XSPContext context = XSPContext.getXSPContext(facesContext);
String entryPage = context.getUrl().getPath() + context.getUrl().getQueryString();
if (entryPage.contains("/home.xsp")) {
this.console("Entry Page contains /home.xsp");
if (this.isBasicMode()) {
entryPage.replace("home.xsp", "basic_Menu.xsp");
}
} else {
this.console("entry page does NOT contain /home.xsp");
}
context.redirectToPage(“/myPage.xsp”);
public void redirectExternal(String url) throws IOException {
FacesContext fc = FacesContext.getCurrentInstance();
ExtenalContext externalContext = fc.getExternalContext();
externalContext.redirect(url);
}
public void redirectToPage(final String pageName) {
// pageName = "/myPage.xsp"
try {
// You'd think this would end all Java processing but that's NOT
// what happens
// It looks like the Java code will finish and only then will the
// redirection happen.
final String entryPage = JSFUtil.getXSPContext().getUrl().getPath() + JSFUtil.getXSPContext().getUrl().getQueryString();
FrameworkUtils.getSessionScope().put("entryPage", entryPage);
this.setEntryPage(entryPage);
JSFUtil.getXSPContext().redirectToPage(pageName);
} catch (final RedirectSignal rs) {
// Ignoring this error. Useless!
}
// Returning false so we can stop the calling code from continuing
// return false;
}
public String getParam(final String key) {
if (!this.getQueryString().containsKey(key)) {
return null;
} else {
return this.getQueryString().get(key);
}
}
#SuppressWarnings("unchecked")
public Map<String, String> getQueryString() {
final Map<String, String> qs = (Map<String, String>) FrameworkUtils.resolveVariable("param");
return qs;
}
depends where your documents files are. It think the best way is create a servlet in the nsf, call that by passing an docUNID and attachmentName. Then you can get the document and write the attachment as stream to the response. If you set the header to attachment, like
response.setHeader("Content-disposition", "attachment; filename=\""+attachment.getName()+"\"");
you will get the attachment as download
Using spring and hibernate.
How can I also send the messages in model too, with the response of that ajax method? I mean whats a better and most practiced way. Any sample code for the three said cases?:
1 returning String
#RequestMapping (value = "/task/delete/{taskId}", method=RequestMethod.GET)
public #ResponseBody String deleteTask(ModelMap model,
#PathVariable(value="taskId") String taskId
){
result = taskService.deleteTask(Long.parseLong(taskId));
if (result.getIsSuccessful()) {
model.put("successMessages", result.getMessageList());
System.out.println("task deleted ------------------");
return "success";//queued - send model message also (if needed)
}else{
System.out.println("task deletion failed ---------------");
model.put("errorMessages", result.getMessageList());
return "failure";//queued - send model message also (if needed)
}
}
2 returning null (no return object required)
#RequestMapping (value = "/attachment/download/{attachmentId}", method=RequestMethod.GET)
public String downloadFile( HttpServletResponse response,
#PathVariable(value = "attachmentId")Long attachmentId
)throws IOException{
result = taskService.getAttachmentById(attachmentId);
if(result.getIsSuccessful()){
Attachment attachment = (Attachment)result.getObject();
File file = new File(attachment.getPath());
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=\"" + file.getName() + "\"");
byte[] ba = FileUtils.readFileToByteArray(file);
response.getOutputStream().write(ba);
}
return null;
//queued - send model message also (if needed)
}
3 returning a full object.
#RequestMapping (value = "/task/create/{parentBoxId}/{taskTitle}/{taskDescription}", method=RequestMethod.GET)
public #ResponseBody Tasks createTask(ModelMap model,
#PathVariable(value="parentBoxId") String parentBoxId,
#PathVariable(value="taskTitle") String taskTitle,
#PathVariable(value="taskDescription") String taskDescription
){
Tasks taskToBeReturned = null;
Tasks task = new Tasks();
task.setTitle(taskTitle);
task.setDescription(taskDescription);
Boxes parentBox = (Boxes)( boxService.getBoxById(Long.valueOf(parentBoxId)) ).getObject();
taskService.setParent(task, parentBox);
result = taskService.save(task);
if(result.getIsSuccessful()){
model.put("successMessages", result.getMessageList());
Tasks savedTask = (Tasks)result.getObject();
System.out.println("box saved title was " + savedTask.getTitle());
taskToBeReturned = new Tasks();
taskToBeReturned.setTitle(savedTask.getTitle());
taskToBeReturned.setId(savedTask.getId());
taskToBeReturned.setDescription(savedTask.getDescription());
}else{
model.put("errorMessages", result.getMessageList());
}
return taskToBeReturned; //queued - send model message also (if needed)
}
I think that the best way to do this is to use a structure like an Hashmap. I'm not sure I really understand what you are trying to do in your "returning null" example, but I think you should probably not returning null from an AJAX call, you should probably return something like the error, it depend on the use case. This can be done in the same way as in the following examples for the other use cases.
Returning a String
#RequestMapping (value = "/task/delete/{taskId}", method=RequestMethod.GET)
public #ResponseBody Map<String, Object> deleteTask(ModelMap model, #PathVariable(value="taskId") String taskId) {
Map<String, Object> result = new HashMap<String, Object>();
result = taskService.deleteTask(Long.parseLong(taskId));
if (result.getIsSuccessful()) {
model.put("successMessages", result.getMessageList());
System.out.println("task deleted ------------------");
result.put("result", "success");
result.put("model", model); // Add the model if needed
}else{
System.out.println("task deletion failed ---------------");
model.put("errorMessages", result.getMessageList());
result.put("result", "failure");
result.put("model", model); // Add the model if needed
}
return result;
}
Returning an Object
#RequestMapping (value = "/task/create/{parentBoxId}/{taskTitle}/{taskDescription}", method=RequestMethod.GET)
public #ResponseBody Map<String, Object> createTask(ModelMap model,
#PathVariable(value="parentBoxId") String parentBoxId,
#PathVariable(value="taskTitle") String taskTitle,
#PathVariable(value="taskDescription") String taskDescription) {
Map<String, Object> result = new HashMap<String, Object>();
Tasks taskToBeReturned = null;
Tasks task = new Tasks();
task.setTitle(taskTitle);
task.setDescription(taskDescription);
Boxes parentBox = (Boxes)( boxService.getBoxById(Long.valueOf(parentBoxId)) ).getObject();
taskService.setParent(task, parentBox);
result = taskService.save(task);
if(result.getIsSuccessful()){
model.put("successMessages", result.getMessageList());
Tasks savedTask = (Tasks)result.getObject();
System.out.println("box saved title was " + savedTask.getTitle());
taskToBeReturned = new Tasks();
taskToBeReturned.setTitle(savedTask.getTitle());
taskToBeReturned.setId(savedTask.getId());
taskToBeReturned.setDescription(savedTask.getDescription());
}else{
model.put("errorMessages", result.getMessageList());
}
result.put("task", taskToBeReturned);
result.put("model", model); // Add the model if needed
return result;
}
I need to log the full http request and response in a JAX-WS WebService call. For the request I need the request headers and the body and for the response, response headers and body.
After some researching, I've found that I can get this information with the property:
-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
and show the information that I need but it dumps it to the console and I need to store it in the database with an internal request id.
I've tried to implement a handler:
public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {
#Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) {
System.out.println("SOAP outbound!!!!!");
Map<String, List<String>> responseHeaders = (Map<String, List<String>>) context
.get(SOAPMessageContext.HTTP_RESPONSE_HEADERS);
try {
String headers = getHeaders(responseHeaders);
System.out.println(headers);
String body = getBody(context.getMessage());
System.out.println(body);
} catch (Exception ex) {
// TODO: What do I have to do in this case?
}
} else {
System.out.println("SOAP inbound!!!!!");
Map<String, List<String>> requestHeaders = (Map<String, List<String>>) context
.get(SOAPMessageContext.HTTP_REQUEST_HEADERS);
try {
String headers = getHeaders(requestHeaders);
System.out.println(headers);
String body = getBody(context.getMessage());
System.out.println(body);
} catch (Exception ex) {
// TODO: What do I have to do in this case?
}
}
return true;
}
private String getBody(SOAPMessage message) throws SOAPException, IOException {
OutputStream stream = new ByteArrayOutputStream();
message.writeTo(stream);
return stream.toString();
}
public String getFullHttpRequest(HttpServletRequest request) throws IOException {
InputStream in = request.getInputStream();
String encoding = request.getCharacterEncoding();
encoding = encoding == null ? "UTF-8" : encoding;
String body = IOUtils.toString(in, encoding);
return body;
}
private String getHeaders(Map<String, List<String>> headers) throws IOException {
StringBuffer result = new StringBuffer();
if (headers != null) {
for (Entry<String, List<String>> header : headers.entrySet()) {
if (header.getValue().isEmpty()) {
// I don't think this is legal, but let's just dump it,
// as the point of the dump is to uncover problems.
result.append(header.getValue());
} else {
for (String value : header.getValue()) {
result.append(header.getKey() + ": " + value);
}
}
result.append("\n");
}
}
return result.toString();
}
}
but in this case, I can get the http request headers and body but in the response, I only get the body, http response headers are always empty.
Any idea on how to archieve this? The objective is to be able to store the full http request and response in a database.
Thanks!!
You could also try
-Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true
I'm assuming you're providing your web service from within a Java EE application server of some sort (and not from a standalone client). You cannot have access to Java EE infrastructure like HttpServletRequest and HttpServletResponse outside of the context of a web/Java EE container.
You could try to get your hands on the actual servlet response object (within a web context) with
HttpServletResponse response = (HttpServletResponse) messageContext.get(SOAPMessageContext.SERVLET_RESPONSE); //messageContext is the SOAPMessageContext
List<String> responseHeaderNames = (List<String>)response.getHeaderNames();
for(String headerName : responseHeaderNames){
//Do whatever you want with it.
}
I seriously doubt that you'll be able to get your hands on the full response headers within a handler though. Your question really intrigued me and I've spent quite some time researching that part. In all the code samples I've seen, Not even the example on the metro site attempt to implement this functionality and I think the reason is simple. As at the point where a handler is invoked, the container may not have enough definitive information to stamp an http header on the outbound message. You might be able to add stuff but that's doubtful as well.