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