org.kohsuke.stapler.RequestImpl Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of stapler Show documentation
Show all versions of stapler Show documentation
Stapler HTTP request handling engine
The newest version!
/*
* Copyright (c) 2004-2010, Kohsuke Kawaguchi
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.kohsuke.stapler;
import net.sf.json.JSON;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONNull;
import net.sf.json.JSONObject;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.jvnet.tiger_types.Lister;
import org.kohsuke.stapler.bind.BoundObjectTable;
import org.kohsuke.stapler.lang.Klass;
import org.kohsuke.stapler.lang.MethodRef;
import org.kohsuke.stapler.util.IllegalReflectiveAccessLogHandler;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import javax.servlet.http.HttpServletResponse;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.logging.Logger;
import java.util.stream.Collectors;
import static java.util.logging.Level.*;
import static javax.servlet.http.HttpServletResponse.*;
/**
* {@link StaplerRequest} implementation.
*
* @author Kohsuke Kawaguchi
*/
public class RequestImpl extends HttpServletRequestWrapper implements StaplerRequest {
/**
* Tokenized URLs and consumed tokens.
* This object is modified by {@link Stapler} as we parse through the URL.
*/
public final TokenList tokens;
/**
* Ancestor nodes traversed so far.
* This object is modified by {@link Stapler} as we parse through the URL.
*/
public final List ancestors;
private final List ancestorsView;
public final Stapler stapler;
private final String originalRequestURI;
/**
* Cached result of {@link #getSubmittedForm()}
*/
private JSONObject structuredForm;
/**
* If the request is "multipart/form-data", parsed result goes here.
*
* @see #parseMultipartFormData()
*/
private Map parsedFormData;
/**
* If the request is "multipart/form-data", the form field only parts of the parsed result go here.
*
* @see #parseMultipartFormData()
*/
private Map parsedFormDataFormFields;
private BindInterceptor bindInterceptor = BindInterceptor.NOOP;
/**
* List of HTTP verbs of requests for which {@link #getSubmittedForm()} can legitimately be called.
* If that method is invoked during a request sent with a different verb, an exception will be thrown.
*/
private static /* nonfinal for Jenkins script console */ List ALLOWED_HTTP_VERBS_FOR_FORMS;
static {
ALLOWED_HTTP_VERBS_FOR_FORMS = Arrays.stream(System.getProperty(RequestImpl.class.getName() + ".ALLOWED_HTTP_VERBS_FOR_FORMS", "POST").split(",")).map(String::trim).collect(Collectors.toList());
}
public RequestImpl(Stapler stapler, HttpServletRequest request, List ancestors, TokenList tokens) {
super(request);
this.stapler = stapler;
this.ancestors = ancestors;
this.ancestorsView = Collections.unmodifiableList(ancestors);
this.tokens = tokens;
this.originalRequestURI = request.getRequestURI();
}
public boolean isJavaScriptProxyCall() {
String ct = getContentType();
return ct!=null && ct.startsWith("application/x-stapler-method-invocation");
}
public BoundObjectTable getBoundObjectTable() {
return stapler.getWebApp().boundObjectTable;
}
public String createJavaScriptProxy(Object toBeExported) {
return getBoundObjectTable().bind(toBeExported).getProxyScript();
}
public Stapler getStapler() {
return stapler;
}
public WebApp getWebApp() {
return stapler.getWebApp();
}
public String getRestOfPath() {
return tokens.assembleRestOfPath();
}
public String getOriginalRestOfPath() {
return tokens.assembleOriginalRestOfPath();
}
public ServletContext getServletContext() {
return stapler.getServletContext();
}
@Override
public String getParameter(String name) {
if(isMultipart()) {
Map data = getFormDataFormFields();
String value = data.get(name);
if (value != null) {
return value;
}
// Fallback ...
}
return super.getParameter(name);
}
@Override
public Map getParameterMap() {
Map parameterMap = super.getParameterMap();
if(isMultipart()) {
Map data = getFormDataFormFields();
parameterMap.putAll(data);
}
return parameterMap;
}
@Override
public Enumeration getParameterNames() {
if(!isMultipart()) {
return super.getParameterNames();
}
Map data = getFormDataFormFields();
if (data.isEmpty()) {
return super.getParameterNames();
}
List paramNames = Collections.list(super.getParameterNames());
paramNames.addAll(data.keySet());
return Collections.enumeration(paramNames);
}
@Override
public String[] getParameterValues(String name) {
if(!isMultipart()) {
return super.getParameterValues(name);
}
Map data = getFormDataFormFields();
if (data.isEmpty()) {
return super.getParameterValues(name);
}
String formFieldVal = data.get(name);
if (formFieldVal == null) {
return super.getParameterValues(name);
}
String[] values = super.getParameterValues(name);
if (values == null) {
values = new String[0];
}
String[] extValues = new String[values.length + 1];
System.arraycopy(values, 0, extValues, 0, values.length);
extValues[extValues.length - 1] = formFieldVal;
return extValues;
}
public String getRequestURIWithQueryString() {
String s = getRequestURI();
String q = getQueryString();
if (q!=null) s+='?'+q;
return s;
}
public StringBuffer getRequestURLWithQueryString() {
StringBuffer s = getRequestURL();
String q = getQueryString();
if (q!=null) s.append('?').append(q);
return s;
}
public RequestDispatcher getView(Object it,String viewName) throws IOException {
return getView(Klass.java(it.getClass()),it,viewName);
}
public RequestDispatcher getView(Class clazz, String viewName) throws IOException {
return getView(Klass.java(clazz),null,viewName);
}
public RequestDispatcher getView(Klass> clazz, String viewName) throws IOException {
return getView(clazz,null,viewName);
}
public RequestDispatcher getView(Klass> clazz, Object it, String viewName) throws IOException {
for( Facet f : stapler.getWebApp().facets ) {
RequestDispatcher rd = f.createRequestDispatcher(this,clazz,it,viewName);
if(rd!=null)
return rd;
}
return null;
}
public String getRootPath() {
StringBuffer buf = super.getRequestURL();
int idx = 0;
for( int i=0; i<3; i++ )
idx += buf.substring(idx).indexOf("/")+1;
buf.setLength(idx-1);
buf.append(super.getContextPath());
return buf.toString();
}
public String getReferer() {
return getHeader("Referer");
}
public List getAncestors() {
return ancestorsView;
}
public Ancestor findAncestor(Class type) {
for( int i = ancestors.size()-1; i>=0; i-- ) {
AncestorImpl a = ancestors.get(i);
Object o = a.getObject();
if (type.isInstance(o))
return a;
}
return null;
}
public T findAncestorObject(Class type) {
Ancestor a = findAncestor(type);
if(a==null) return null;
return type.cast(a.getObject());
}
public Ancestor findAncestor(Object anc) {
for( int i = ancestors.size()-1; i>=0; i-- ) {
AncestorImpl a = ancestors.get(i);
Object o = a.getObject();
if (o==anc)
return a;
}
return null;
}
public boolean hasParameter(String name) {
return getParameter(name)!=null;
}
public String getOriginalRequestURI() {
return originalRequestURI;
}
public boolean checkIfModified(long lastModified, StaplerResponse rsp) {
return checkIfModified(lastModified,rsp,0);
}
public boolean checkIfModified(long lastModified, StaplerResponse rsp, long expiration) {
if(lastModified<=0)
return false;
// send out Last-Modified, or check If-Modified-Since
String since = getHeader("If-Modified-Since");
SimpleDateFormat format = Stapler.HTTP_DATE_FORMAT.get();
if(since!=null) {
try {
long ims = format.parse(since).getTime();
if(lastModified
List bindParametersToList(Class type, String prefix) {
List r = new ArrayList();
int len = Integer.MAX_VALUE;
Enumeration e = getParameterNames();
while(e.hasMoreElements()) {
String name = (String)e.nextElement();
if(name.startsWith(prefix))
len = Math.min(len,getParameterValues(name).length);
}
if(len==Integer.MAX_VALUE)
return r; // nothing
try {
new ClassDescriptor(type).loadConstructorParamNames();
// use the designated constructor for databinding
for( int i=0; i T bindParameters(Class type, String prefix) {
return bindParameters(type,prefix,0);
}
public T bindParameters(Class type, String prefix, int index) {
String[] names = new ClassDescriptor(type).loadConstructorParamNames();
// the actual arguments to invoke the constructor with.
Object[] args = new Object[names.length];
// constructor
Constructor c = findConstructor(type, names.length);
Class[] types = c.getParameterTypes();
// convert parameters
for( int i=0; i T bindJSON(Class type, JSONObject src) {
return type.cast(bindJSON(type, type, src));
}
public Object bindJSON(Type type, Class erasure, Object json) {
return new TypePair(type,erasure).convertJSON(json);
}
public void bindJSON(Object bean, JSONObject src) {
try {
for( String key : (Set)src.keySet() ) {
TypePair type = getPropertyType(bean, key);
if(type==null)
continue;
try {
fill(bean,key, type.convertJSON(src.get(key)));
} catch (WrongTypeException e) {
throw new IllegalArgumentException(String.format("Error binding field %s: %s", key, e.getMessage()));
}
}
} catch (IllegalAccessException e) {
IllegalAccessError x = new IllegalAccessError(e.getMessage());
x.initCause(e);
throw x;
} catch (InvocationTargetException x) {
Throwable e = x.getTargetException();
if(e instanceof RuntimeException)
throw (RuntimeException)e;
if(e instanceof Error)
throw (Error)e;
throw new RuntimeException(x);
}
}
public List bindJSONToList(Class type, Object src) {
ArrayList r = new ArrayList();
if (src instanceof JSONObject) {
JSONObject j = (JSONObject) src;
r.add(bindJSON(type,j));
}
if (src instanceof JSONArray) {
JSONArray a = (JSONArray) src;
for (Object o : a) {
if (o instanceof JSONObject) {
JSONObject j = (JSONObject) o;
r.add(bindJSON(type,j));
}
}
}
return r;
}
private T invokeConstructor(Constructor c, Object[] args) {
try {
return c.newInstance(args);
} catch (InstantiationException e) {
InstantiationError x = new InstantiationError(e.getMessage());
x.initCause(e);
throw x;
} catch (IllegalAccessException e) {
IllegalAccessError x = new IllegalAccessError(e.getMessage());
x.initCause(e);
throw x;
} catch (InvocationTargetException e) {
Throwable x = e.getTargetException();
if(x instanceof Error)
throw (Error)x;
if(x instanceof RuntimeException)
throw (RuntimeException)x;
throw new IllegalArgumentException(x);
} catch (IllegalArgumentException e) {
throw new IllegalArgumentException("Failed to invoke "+c+" with "+ Arrays.asList(args),e);
}
}
private Constructor findConstructor(Class type, int length) {
Constructor>[] ctrs = type.getConstructors();
// one with DataBoundConstructor is the most reliable
for (Constructor c : ctrs) {
if(c.getAnnotation(DataBoundConstructor.class)!=null) {
if(c.getParameterTypes().length!=length)
throw new IllegalArgumentException(c+" has @DataBoundConstructor but it doesn't match with your .stapler file. Try clean rebuild");
return c;
}
}
// if not, maybe this was from @stapler-constructor,
// so look for the constructor with the expected argument length.
// this is not very reliable.
for (Constructor c : ctrs) {
if(c.getParameterTypes().length==length)
return c;
}
throw new IllegalArgumentException(type+" does not have a constructor with "+length+" arguments");
}
private static void fill(Object bean, String key, Object value) {
StringTokenizer tokens = new StringTokenizer(key);
while(tokens.hasMoreTokens()) {
String token = tokens.nextToken();
boolean last = !tokens.hasMoreTokens(); // is this the last token?
try {
if(last) {
copyProperty(bean,token,value);
} else {
bean = BeanUtils.getProperty(bean,token);
}
} catch (IllegalAccessException x) {
throw new IllegalAccessError(x.getMessage());
} catch (InvocationTargetException x) {
Throwable e = x.getTargetException();
if(e instanceof RuntimeException)
throw (RuntimeException)e;
if(e instanceof Error)
throw (Error)e;
throw new RuntimeException(x);
} catch (NoSuchMethodException e) {
// ignore if there's no such property
}
}
}
/**
* Information about the type.
*/
private final class TypePair {
final Type genericType;
/**
* Erasure of {@link #genericType}
*/
final Class type;
TypePair(Type genericType, Class type) {
this.genericType = genericType;
this.type = type;
}
TypePair(Field f) {
this(f.getGenericType(),f.getType());
}
/**
* Converts the given JSON object (either {@link JSONObject}, {@link JSONArray}, or other primitive types
* in JSON, to the type represented by the 'this' object.
*/
public Object convertJSON(Object o) {
Object r = bindInterceptor.onConvert(genericType, type, o);
if (r!= BindInterceptor.DEFAULT) return r; // taken over by the interceptor
for (BindInterceptor i : getWebApp().bindInterceptors) {
r = i.onConvert(genericType, type, o);
if (r!= BindInterceptor.DEFAULT) return r; // taken over by the interceptor
}
if(o==null || o instanceof JSONNull) {
// this method returns null if the type is not primitive, which works.
return ReflectionUtils.getVmDefaultValueFor(type);
}
if (type==JSONArray.class) {
if (o instanceof JSONArray) return o;
JSONArray a = new JSONArray();
a.add(o);
return a;
}
Lister l = Lister.create(type,genericType);
if (o instanceof JSONObject) {
JSONObject j = (JSONObject) o;
if (j.isNullObject()) // another flavor of null. json-lib sucks.
return ReflectionUtils.getVmDefaultValueFor(type);
if(l==null) {// single value conversion
try {
Class actualType = type;
String className = null;
if(j.has("stapler-class")) {
// deprecated as of 2.4-jenkins-4 but left here for a while until we are sure nobody uses this
className = j.getString("stapler-class");
LOGGER.log(FINE, "stapler-class is deprecated in favor of $class: {0}", className);
}
if(j.has("$class")) {
className = j.getString("$class");
}
if (className != null) {
// sub-type is specified in JSON.
// note that this can come from malicious clients, so we need to make sure we don't have security issues.
ClassLoader cl = stapler.getWebApp().getClassLoader();
try {
Class> subType = cl.loadClass(className);
if(!actualType.isAssignableFrom(subType))
throw new IllegalArgumentException("Specified type "+subType+" is not assignable to the expected "+actualType);
actualType = (Class)subType; // I'm being lazy here
} catch (ClassNotFoundException e) {
throw new IllegalArgumentException("Class "+className+" is specified in JSON, but no such class found in "+cl,e);
}
}
return instantiate(actualType, j);
} catch (IllegalArgumentException e) {
JSONObject sanitizedJson = getWebApp().getJsonInErrorMessageSanitizer().sanitize(j);
throw new IllegalArgumentException("Failed to instantiate "+type+" from "+sanitizedJson,e);
}
} else {// collection conversion
if(j.has("stapler-class-bag")) {
// this object is a hash from class names to their parameters
// build them into a collection via Lister
ClassLoader cl = stapler.getWebApp().getClassLoader();
for (Map.Entry e : (Set>)j.entrySet()) {
Object v = e.getValue();
String className = e.getKey().replace('-','.'); // decode JSON-safe class name escaping
try {
Class> itemType = cl.loadClass(className);
if (v instanceof JSONObject) {
l.add(bindJSON(itemType, (JSONObject) v));
}
if (v instanceof JSONArray) {
for(Object i : bindJSONToList(itemType, (JSONArray) v))
l.add(i);
}
} catch (ClassNotFoundException e1) {
// ignore unrecognized element
}
}
} else if (Enum.class.isAssignableFrom(l.itemType)) {
// this is a hash of element names as enum constant names
for (Map.Entry e : (Set>)j.entrySet()) {
Object v = e.getValue();
if (v==null || (v instanceof Boolean && !(Boolean)v))
continue; // skip if the value is null or false
l.add(Enum.valueOf(l.itemType,e.getKey()));
}
} else {
// only one value given to the collection
l.add(new TypePair(l.itemGenericType,l.itemType).convertJSON(j));
}
return l.toCollection();
}
}
if (o instanceof JSONArray) {
if (l == null)
throw new WrongTypeException(String.format("Got type array but no lister class found for type %s", type));
JSONArray a = (JSONArray) o;
TypePair itemType = new TypePair(l.itemGenericType,l.itemType);
for (Object item : a)
l.add(itemType.convertJSON(item));
return l.toCollection();
}
if(Enum.class.isAssignableFrom(type))
return Enum.valueOf(type,o.toString());
if (l==null) {// single value conversion
Converter converter = Stapler.lookupConverter(type);
if (converter == null) {
if (type == Object.class) {
return o;
}
throw new IllegalArgumentException("Unable to convert to "+type);
}
return converter.convert(type,o);
} else {// single value in a collection
Converter converter = Stapler.lookupConverter(l.itemType);
if (converter == null) {
if (l.itemType == Object.class) {
l.add(o);
} else {
throw new IllegalArgumentException("Unable to convert to "+l.itemType);
}
} else {
l.add(converter.convert(l.itemType, o));
}
return l.toCollection();
}
}
}
/**
* Called after the actual type of the binding is figured out.
*/
private Object instantiate(Class actualType, JSONObject j) {
Object r = bindInterceptor.instantiate(actualType,j);
if (r!=BindInterceptor.DEFAULT) return r;
for (BindInterceptor bi : getWebApp().bindInterceptors) {
r = bi.instantiate(actualType,j);
if (r!=BindInterceptor.DEFAULT) return r;
}
if (actualType==JSONObject.class || actualType==JSON.class) return actualType.cast(j);
String[] names = new ClassDescriptor(actualType).loadConstructorParamNames();
// the actual arguments to invoke the constructor with.
Object[] args = new Object[names.length];
// constructor
Constructor c = findConstructor(actualType, names.length);
Class[] types = c.getParameterTypes();
Type[] genTypes = c.getGenericParameterTypes();
// convert parameters
for( int i=0; i T injectSetters(T r, JSONObject j, Collection exclusions) {
// try to assign rest of the properties
OUTER:
for (String key : (Set)j.keySet()) {
if (!exclusions.contains(key)) {
try {
// try field injection first
for (Class c=r.getClass(); c!=null; c=c.getSuperclass()) {
try {
Field f = c.getDeclaredField(key);
if (f.getAnnotation(DataBoundSetter.class)!=null) {
try {
f.set(r, bindJSON(f.getGenericType(), f.getType(), j.get(key)));
} catch(IllegalAccessException e) {
LOGGER.warning(IllegalReflectiveAccessLogHandler.get(e));
f.setAccessible(true);
f.set(r, bindJSON(f.getGenericType(), f.getType(), j.get(key)));
}
continue OUTER;
}
} catch (NoSuchFieldException e) {
// recurse into parents
}
}
Method wm = findDataBoundSetter(r.getClass(), key);
if (wm==null) continue;
Class>[] pt = wm.getParameterTypes();
assert pt.length==1;
// only invoking public methods for security reasons
wm.invoke(r, bindJSON(wm.getGenericParameterTypes()[0], pt[0], j.get(key)));
} catch (IllegalAccessException e) {
LOGGER.log(WARNING, "Cannot access property " + key + " of " + r.getClass(), e);
} catch (InvocationTargetException e) {
LOGGER.log(WARNING, "Cannot access property " + key + " of " + r.getClass(), e);
}
}
}
invokePostConstruct(getWebApp().getMetaClass(r).getPostConstructMethods(), r);
return r;
}
private Method findDataBoundSetter(Class c, String name) {
// look for public setter that has the matching name
for ( ; c!=null; c=c.getSuperclass()) {
for (Method m : c.getDeclaredMethods()) {
if (!Modifier.isPublic(m.getModifiers())
|| !m.getName().startsWith("set")
|| m.getParameterTypes().length!=1
|| !m.isAnnotationPresent(DataBoundSetter.class))
continue;
String propertyName = Introspector.decapitalize(m.getName().substring(3));
if (!name.equals(propertyName))
continue; // not the name we are looking for
return m;
}
}
return null;
}
/**
* Invoke PostConstruct method from the base class to subtypes.
*/
private void invokePostConstruct(SingleLinkedList methods, Object r) {
if (methods.isEmpty()) return;
invokePostConstruct(methods.tail,r);
try {
methods.head.invoke(r);
} catch (InvocationTargetException e) {
throw new IllegalArgumentException("Unable to post-construct "+r,e);
} catch (IllegalAccessException e) {
throw (Error)new IllegalAccessError().initCause(e);
}
}
/**
* Gets the type of the field/property designate by the given name.
*/
private TypePair getPropertyType(Object bean, String name) throws IllegalAccessException, InvocationTargetException {
try {
PropertyDescriptor propDescriptor = PropertyUtils.getPropertyDescriptor(bean, name);
if(propDescriptor!=null) {
Method m = propDescriptor.getWriteMethod();
if(m!=null)
return new TypePair(m.getGenericParameterTypes()[0], m.getParameterTypes()[0]);
}
} catch (NoSuchMethodException e) {
// no such property
}
// try a field
try {
return new TypePair(bean.getClass().getField(name));
} catch (NoSuchFieldException e) {
// no such field
}
return null;
}
/**
* Sets the property/field value of the given name, by performing a value type conversion if necessary.
*/
private static void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException {
PropertyDescriptor propDescriptor;
try {
propDescriptor =
PropertyUtils.getPropertyDescriptor(bean, name);
} catch (NoSuchMethodException e) {
propDescriptor = null;
}
if ((propDescriptor != null) &&
(propDescriptor.getWriteMethod() == null)) {
propDescriptor = null;
}
if (propDescriptor != null) {
Converter converter = Stapler.lookupConverter(propDescriptor.getPropertyType());
if (converter != null)
value = converter.convert(propDescriptor.getPropertyType(), value);
try {
PropertyUtils.setSimpleProperty(bean, name, value);
} catch (NoSuchMethodException e) {
throw new NoSuchMethodError(e.getMessage());
}
return;
}
// try a field
try {
Field field = bean.getClass().getField(name);
Converter converter = ConvertUtils.lookup(field.getType());
if (converter != null)
value = converter.convert(field.getType(), value);
field.set(bean,value);
} catch (NoSuchFieldException e) {
// no such field
}
}
private void parseMultipartFormData() throws ServletException {
if(parsedFormData!=null) return;
parsedFormData = new HashMap();
parsedFormDataFormFields = new HashMap();
ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());
try {
for( FileItem fi : (List)upload.parseRequest(this) ) {
parsedFormData.put(fi.getFieldName(),fi);
if (fi.isFormField()) {
parsedFormDataFormFields.put(fi.getFieldName(),fi.getString());
}
}
} catch (FileUploadException e) {
throw new ServletException(e);
}
}
/**
* A version of parseMultipartFormData() that doesn't throw exceptions.
*/
private Map getFormDataFormFields() {
try {
parseMultipartFormData();
} catch (Exception e) {
LOGGER.log(SEVERE, "Error parsing multipart/form-data.", e);
}
return parsedFormDataFormFields;
}
public JSONObject getSubmittedForm() throws ServletException {
final String method = this.getMethod();
if (!ALLOWED_HTTP_VERBS_FOR_FORMS.contains(method)) {
throw HttpResponses.errorWithoutStack(SC_BAD_REQUEST, "Form submission expected but a " + method + " request was sent");
}
if(structuredForm==null) {
String p = null;
boolean isSubmission; // for error diagnosis, if something is submitted, set to true
if(isMultipart()) {
isSubmission=true;
parseMultipartFormData();
FileItem item = parsedFormData.get("json");
if(item!=null) {
if (item.getContentType() == null && getCharacterEncoding() != null) {
// JENKINS-11543: If client doesn't set charset per part, use request encoding
try {
p = item.getString(getCharacterEncoding());
} catch (java.io.UnsupportedEncodingException uee) {
LOGGER.log(WARNING, "Request has unsupported charset, using default for 'json' parameter", uee);
p = item.getString();
}
} else {
p = item.getString();
}
}
} else {
p = getParameter("json");
isSubmission = !getParameterMap().isEmpty();
}
if(p==null || p.length() == 0) {
// no data submitted
try {
StaplerResponse rsp = Stapler.getCurrentResponse();
if(isSubmission)
rsp.sendError(SC_BAD_REQUEST,"This page expects a form submission");
else
rsp.sendError(SC_BAD_REQUEST,"Nothing is submitted");
throw new ServletException("This page expects a form submission but had only " + getParameterMap());
} catch (IOException e) {
throw new ServletException(e);
}
}
try {
structuredForm = JSONObject.fromObject(p);
} catch (JSONException e) {
throw new ServletException("Failed to parse JSON:" + p, e);
}
}
return structuredForm;
}
private boolean isMultipart() {
String ct = getContentType();
return (ct!=null && ct.startsWith("multipart/"));
}
public FileItem getFileItem(String name) throws ServletException, IOException {
parseMultipartFormData();
if(parsedFormData==null) return null;
FileItem item = parsedFormData.get(name);
if(item==null || item.isFormField()) return null;
return item;
}
private static final Logger LOGGER = Logger.getLogger(RequestImpl.class.getName());
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy