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    }