001 package railo.runtime.type.scope; 002 003 import java.io.BufferedReader; 004 import java.io.File; 005 import java.io.InputStream; 006 import java.io.UnsupportedEncodingException; 007 import java.util.ArrayList; 008 import java.util.Iterator; 009 import java.util.Map; 010 011 import javax.servlet.ServletInputStream; 012 import javax.servlet.http.HttpServletRequest; 013 014 import org.apache.commons.fileupload.FileItemFactory; 015 import org.apache.commons.fileupload.FileItemIterator; 016 import org.apache.commons.fileupload.FileItemStream; 017 import org.apache.commons.fileupload.disk.DiskFileItem; 018 import org.apache.commons.fileupload.disk.DiskFileItemFactory; 019 import org.apache.commons.fileupload.servlet.ServletFileUpload; 020 import org.apache.commons.fileupload.servlet.ServletRequestContext; 021 022 import railo.commons.collections.HashTable; 023 import railo.commons.io.IOUtil; 024 import railo.commons.io.res.Resource; 025 import railo.commons.lang.ByteNameValuePair; 026 import railo.commons.lang.StringUtil; 027 import railo.commons.net.URLItem; 028 import railo.runtime.PageContext; 029 import railo.runtime.config.ConfigImpl; 030 import railo.runtime.engine.ThreadLocalPageContext; 031 import railo.runtime.exp.PageException; 032 import railo.runtime.listener.ApplicationContext; 033 import railo.runtime.net.http.ServletInputStreamDummy; 034 import railo.runtime.op.Caster; 035 import railo.runtime.type.Array; 036 import railo.runtime.type.util.ArrayUtil; 037 import railo.runtime.type.util.KeyConstants; 038 import railo.runtime.type.util.ListUtil; 039 040 041 /** 042 * Form Scope 043 */ 044 public final class FormImpl extends ScopeSupport implements Form,ScriptProtected { 045 046 047 private byte EQL=61; 048 private byte NL=10; 049 private byte AMP=38; 050 051 052 private HashTable fileItems=new HashTable(); 053 private Exception initException=null; 054 055 private String encoding=null; 056 private int scriptProtected=ScriptProtected.UNDEFINED; 057 private static final URLItem[] empty=new URLItem[0]; 058 //private static final ResourceFilter FILTER = new ExtensionResourceFilter(".upload",false); 059 private URLItem[] raw=empty; 060 private static int count=1; 061 062 private static final int HEADER_TEXT_PLAIN=0; 063 private static final int HEADER_MULTIPART_FORM_DATA=1; 064 private static final int HEADER_APP_URL_ENC=2; 065 private int headerType=-1; 066 067 /** 068 * standart class Constructor 069 */ 070 public FormImpl() { 071 super(true,"form",SCOPE_FORM); 072 } 073 074 @Override 075 public String getEncoding() { 076 return encoding; 077 } 078 079 @Override 080 public void setEncoding(ApplicationContext ac,String encoding) throws UnsupportedEncodingException { 081 encoding=encoding.trim().toUpperCase(); 082 if(encoding.equals(this.encoding)) return; 083 this.encoding = encoding; 084 if(!isInitalized()) return; 085 fillDecoded(raw,encoding,isScriptProtected(),ac.getSameFieldAsArray(Scope.SCOPE_FORM)); 086 setFieldNames(); 087 } 088 089 @Override 090 public void initialize(PageContext pc) { 091 if(encoding==null)encoding=pc.getConfig().getWebCharset(); 092 093 if(scriptProtected==ScriptProtected.UNDEFINED) { 094 scriptProtected=((pc.getApplicationContext().getScriptProtect()&ApplicationContext.SCRIPT_PROTECT_FORM)>0)? 095 ScriptProtected.YES:ScriptProtected.NO; 096 } 097 super.initialize(pc); 098 099 String contentType=pc. getHttpServletRequest().getContentType(); 100 101 if(contentType==null) return; 102 contentType=StringUtil.toLowerCase(contentType); 103 if(contentType.startsWith("multipart/form-data")) { 104 headerType=HEADER_MULTIPART_FORM_DATA; 105 initializeMultiPart(pc,isScriptProtected()); 106 } 107 else if(contentType.startsWith("text/plain")) { 108 headerType=HEADER_TEXT_PLAIN; 109 initializeUrlEncodedOrTextPlain(pc,'\n',isScriptProtected()); 110 } 111 else { 112 headerType=HEADER_APP_URL_ENC; 113 initializeUrlEncodedOrTextPlain(pc,'&',isScriptProtected()); 114 } 115 setFieldNames(); 116 } 117 118 void setFieldNames() { 119 if(size()>0) { 120 setEL(KeyConstants._fieldnames,ListUtil.arrayToList(keys(), ",")); 121 } 122 } 123 124 125 private void initializeMultiPart(PageContext pc, boolean scriptProteced) { 126 // get temp directory 127 Resource tempDir = ((ConfigImpl)pc.getConfig()).getTempDirectory(); 128 Resource tempFile; 129 130 // Create a new file upload handler 131 final String encoding=getEncoding(); 132 FileItemFactory factory = tempDir instanceof File? 133 new DiskFileItemFactory(DiskFileItemFactory.DEFAULT_SIZE_THRESHOLD,(File)tempDir): 134 new DiskFileItemFactory(); 135 136 ServletFileUpload upload = new ServletFileUpload(factory); 137 upload.setHeaderEncoding(encoding); 138 //ServletRequestContext c = new ServletRequestContext(pc.getHttpServletRequest()); 139 140 141 HttpServletRequest req = pc.getHttpServletRequest(); 142 ServletRequestContext context = new ServletRequestContext(req) { 143 public String getCharacterEncoding() { 144 return encoding; 145 } 146 }; 147 148 // Parse the request 149 try { 150 FileItemIterator iter = upload.getItemIterator(context); 151 //byte[] value; 152 InputStream is; 153 ArrayList list=new ArrayList(); 154 while (iter.hasNext()) { 155 FileItemStream item = iter.next(); 156 157 is=IOUtil.toBufferedInputStream(item.openStream()); 158 if (item.getContentType()==null || StringUtil.isEmpty(item.getName())) { 159 list.add(new URLItem(item.getFieldName(),new String(IOUtil.toBytes(is),encoding),false)); 160 } 161 else { 162 tempFile=tempDir.getRealResource(getFileName()); 163 fileItems.put(item.getFieldName().toLowerCase(), 164 new Item(tempFile,item.getContentType(),item.getName(),item.getFieldName())); 165 String value=tempFile.toString(); 166 IOUtil.copy(is, tempFile,true); 167 168 list.add(new URLItem(item.getFieldName(),value,false)); 169 } 170 } 171 172 raw=(URLItem[]) list.toArray(new URLItem[list.size()]); 173 fillDecoded(raw,encoding,scriptProteced,pc.getApplicationContext().getSameFieldAsArray(SCOPE_FORM)); 174 } 175 catch (Exception e) { 176 177 //throw new PageRuntimeException(Caster.toPageException(e)); 178 fillDecodedEL(new URLItem[0],encoding,scriptProteced,pc.getApplicationContext().getSameFieldAsArray(SCOPE_FORM)); 179 initException=e; 180 } 181 } 182 183 private static String getFileName() { 184 return "tmp-"+(count++)+".upload"; 185 } 186 187 /*private void initializeMultiPart(PageContext pc, boolean scriptProteced) { 188 189 File tempDir=FileWrapper.toFile(pc.getConfig().getTempDirectory()); 190 191 // Create a factory for disk-based file items 192 DiskFileItemFactory factory = new DiskFileItemFactory(-1,tempDir); 193 194 // Create a new file upload handler 195 ServletFileUpload upload = new ServletFileUpload(factory); 196 197 upload.setHeaderEncoding(getEncoding()); 198 199 //FileUpload fileUpload=new FileUpload(new DiskFileItemFactory(0,tempDir)); 200 java.util.List list; 201 try { 202 list = upload.parseRequest(pc.getHttpServletRequest()); 203 raw=new ByteNameValuePair[list.size()]; 204 205 for(int i=0;i<raw.length;i++) { 206 DiskFileItem val=(DiskFileItem) list.get(i); 207 if(val.isFormField()) { 208 raw[i]=new ByteNameValuePair(getBytes(val.getFieldName()),val.get(),false); 209 } 210 else { 211 print.out("-------------------------------"); 212 print.out("fieldname:"+val.getFieldName()); 213 print.out("name:"+val.getName()); 214 print.out("formfield:"+val.isFormField()); 215 print.out("memory:"+val.isInMemory()); 216 print.out("exist:"+val.getStoreLocation().getCanonicalFile().exists()); 217 218 fileItems.put(val.getFieldName().toLowerCase(),val); 219 220 raw[i]=new ByteNameValuePair(getBytes(val.getFieldName()),val.getStoreLocation().getCanonicalFile().toString().getBytes(),false); 221 //raw.put(val.getFieldName(),val.getStoreLocation().getCanonicalFile().toString()); 222 } 223 } 224 fillDecoded(raw,encoding,scriptProteced); 225 } 226 catch (Exception e) { 227 228 //throw new PageRuntimeException(Caster.toPageException(e)); 229 fillDecodedEL(new ByteNameValuePair[0],encoding,scriptProteced); 230 initException=e; 231 } 232 }*/ 233 234 private void initializeUrlEncodedOrTextPlain(PageContext pc, char delimiter, boolean scriptProteced) { 235 BufferedReader reader=null; 236 try { 237 reader = pc.getHttpServletRequest().getReader(); 238 raw=setFrom___(IOUtil.toString(reader,false),delimiter); 239 fillDecoded(raw,encoding,scriptProteced,pc.getApplicationContext().getSameFieldAsArray(SCOPE_FORM)); 240 } 241 catch (Exception e) { 242 243 fillDecodedEL(new URLItem[0],encoding,scriptProteced,pc.getApplicationContext().getSameFieldAsArray(SCOPE_FORM)); 244 initException=e; 245 } 246 finally { 247 IOUtil.closeEL(reader); 248 } 249 } 250 251 252 @Override 253 public void release() { 254 release(ThreadLocalPageContext.get()); 255 } 256 257 @Override 258 public void release(PageContext pc) { 259 super.release(pc); 260 encoding=null; 261 scriptProtected=ScriptProtected.UNDEFINED; 262 raw=empty; 263 264 if(!fileItems.isEmpty()) { 265 Iterator it = fileItems.entrySet().iterator(); 266 Item item; 267 while(it.hasNext()) { 268 item=(Item) ((Map.Entry) it.next()).getValue(); 269 item.getResource().delete(); 270 } 271 fileItems.clear(); 272 } 273 initException=null; 274 275 } 276 277 @Override 278 public FormItem[] getFileItems() { 279 if(fileItems==null || fileItems.isEmpty()) return new FormImpl.Item[0]; 280 281 Iterator it = fileItems.entrySet().iterator(); 282 Map.Entry entry; 283 FormImpl.Item[] rtn=new FormImpl.Item[fileItems.size()]; 284 int index=0; 285 while(it.hasNext()){ 286 entry=(Entry) it.next(); 287 rtn[index++]=(Item) entry.getValue(); 288 } 289 return rtn; 290 } 291 292 293 public DiskFileItem getFileUpload(String key) { 294 return null; 295 } 296 297 public FormItem getUploadResource(String key) { 298 key=key.trim(); 299 String lcKey = StringUtil.toLowerCase(key); 300 301 // x 302 Item item = (Item) fileItems.get(lcKey); 303 if(item!=null)return item; 304 305 // form.x 306 if(lcKey.startsWith("form.")) { 307 lcKey=lcKey.substring(5).trim(); 308 item = (Item) fileItems.get(lcKey); 309 if(item!=null)return item; 310 } 311 312 // form . x 313 try { 314 Array array = ListUtil.listToArray(lcKey, '.'); 315 if(array.size()>1 && array.getE(1).toString().trim().equals("form")) { 316 array.removeE(1); 317 lcKey=ListUtil.arrayToList(array, ".").trim(); 318 item = (Item) fileItems.get(lcKey); 319 if(item!=null)return item; 320 } 321 } 322 catch (PageException e) {} 323 324 // /file.tmp 325 Iterator it = fileItems.entrySet().iterator(); 326 //print.out("------------------"); 327 while(it.hasNext()) { 328 item=(Item) ((Map.Entry)it.next()).getValue(); 329 //print.out(item.getResource().getAbsolutePath()+" - "+key); 330 //try { 331 //if(item.getStoreLocation().getCanonicalFile().toString().equalsIgnoreCase(key))return item; 332 if(item.getResource().getAbsolutePath().equalsIgnoreCase(key))return item; 333 //} 334 //catch (IOException e) {} 335 } 336 337 return null; 338 } 339 340 @Override 341 public PageException getInitException() { 342 if(initException!=null) 343 return Caster.toPageException(initException); 344 return null; 345 } 346 347 @Override 348 public void setScriptProtecting(ApplicationContext ac,boolean scriptProtected) { 349 int _scriptProtected = scriptProtected?ScriptProtected.YES:ScriptProtected.NO; 350 if(isInitalized() && _scriptProtected!=this.scriptProtected) { 351 fillDecodedEL(raw,encoding,scriptProtected,ac.getSameFieldAsArray(SCOPE_FORM)); 352 setFieldNames(); 353 } 354 this.scriptProtected=_scriptProtected; 355 } 356 357 @Override 358 public boolean isScriptProtected() { 359 return scriptProtected==ScriptProtected.YES ; 360 } 361 362 /** 363 * @return the raw 364 */ 365 public URLItem[] getRaw() { 366 return raw; 367 } 368 369 public void addRaw(ApplicationContext ac,URLItem[] raw) { 370 URLItem[] nr=new URLItem[this.raw.length+raw.length]; 371 for(int i=0;i<this.raw.length;i++) { 372 nr[i]=this.raw[i]; 373 } 374 for(int i=0;i<raw.length;i++) { 375 nr[this.raw.length+i]=raw[i]; 376 } 377 this.raw=nr; 378 379 if(!isInitalized()) return; 380 fillDecodedEL(this.raw,encoding,isScriptProtected(),ac.getSameFieldAsArray(SCOPE_FORM)); 381 setFieldNames(); 382 } 383 384 private class Item implements FormItem { 385 Resource resource; 386 String contentType; 387 String name; 388 private String fieldName; 389 390 public Item(Resource resource, String contentType,String name, String fieldName) { 391 this.fieldName = fieldName; 392 this.name = name; 393 this.resource = resource; 394 this.contentType = contentType; 395 } 396 /** 397 * @return the resource 398 */ 399 public Resource getResource() { 400 return resource; 401 } 402 /** 403 * @return the contentType 404 */ 405 public String getContentType() { 406 return contentType; 407 } 408 /** 409 * @return the name 410 */ 411 public String getName() { 412 return name; 413 } 414 /** 415 * @return the fieldName 416 */ 417 public String getFieldName() { 418 return fieldName; 419 } 420 } 421 422 /** 423 * @return return content as a http header input stream 424 */ 425 public ServletInputStream getInputStream() { 426 if(headerType==HEADER_APP_URL_ENC) { 427 return new ServletInputStreamDummy(toBarr(raw,AMP)); 428 } 429 else if(headerType==HEADER_TEXT_PLAIN) { 430 return new ServletInputStreamDummy(toBarr(raw,NL)); 431 } 432 /*else if(headerType==HEADER_MULTIPART_FORM_DATA) { 433 return new FormImplInputStream(this); 434 // TODO 435 }*/ 436 return new ServletInputStreamDummy(new byte[]{}); 437 } 438 439 private byte[] toBarr(URLItem[] items, byte del) { 440 441 ByteNameValuePair[] raw=new ByteNameValuePair[items.length]; 442 for(int i=0;i<raw.length;i++) { 443 try { 444 raw[i]=new ByteNameValuePair(items[i].getName().getBytes("iso-8859-1"),items[i].getValue().getBytes("iso-8859-1"),items[i].isUrlEncoded()); 445 } catch (UnsupportedEncodingException e) {} 446 } 447 448 int size=0; 449 if(!ArrayUtil.isEmpty(raw)){ 450 for(int i=0;i<raw.length;i++) { 451 size+=raw[i].getName().length; 452 size+=raw[i].getValue().length; 453 size+=2; 454 } 455 size--; 456 } 457 byte[] barr = new byte[size],bname,bvalue; 458 int count=0; 459 460 for(int i=0;i<raw.length;i++) { 461 bname=raw[i].getName(); 462 bvalue=raw[i].getValue(); 463 // name 464 for(int y=0;y<bname.length;y++) { 465 barr[count++]=bname[y]; 466 } 467 barr[count++]=EQL; 468 // value 469 for(int y=0;y<bvalue.length;y++) { 470 barr[count++]=bvalue[y]; 471 } 472 if(i+1<raw.length)barr[count++]=del; 473 } 474 return barr; 475 } 476 477 }