Package com.caucho.quercus.env

Source Code of com.caucho.quercus.env.Post

/*
* Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT.  See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
*   Free Software Foundation, Inc.
*   59 Temple Place, Suite 330
*   Boston, MA 02111-1307  USA
*
* @author Scott Ferguson
*/

package com.caucho.quercus.env;

import com.caucho.quercus.lib.string.StringModule;
import com.caucho.quercus.lib.string.StringUtility;
import com.caucho.quercus.lib.file.FileModule;
import com.caucho.vfs.FilePath;
import com.caucho.vfs.MultipartStream;
import com.caucho.vfs.Path;
import com.caucho.vfs.ReadStream;
import com.caucho.vfs.VfsStream;
import com.caucho.vfs.WriteStream;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.Set;

/**
* Handling of POST requests.
*/
public class Post {
  static void fillPost(Env env,
                       ArrayValue postArray, ArrayValue files,
                       HttpServletRequest request,
                       boolean addSlashesToValues)
  {
    InputStream is = null;

    try {
      if (request.getMethod().equals("POST")) {
        String encoding = request.getCharacterEncoding();
       
        if (encoding == null)
          encoding = env.getHttpInputEncoding();

        String contentType = request.getHeader("Content-Type");

        is = request.getInputStream();
       
        if (contentType != null
            && contentType.startsWith("multipart/form-data")) {
          String boundary = getBoundary(contentType);

          ReadStream rs = new ReadStream(new VfsStream(is, null));
          MultipartStream ms = new MultipartStream(rs, boundary);
         
          if (encoding != null)
            ms.setEncoding(encoding);

          readMultipartStream(env, ms, postArray, files, addSlashesToValues, encoding);

          rs.close();
        }
        else {
          StringValue bb = env.createBinaryBuilder();
         
          bb.appendReadAll(is, Integer.MAX_VALUE);
         
          env.setInputData(bb);
         
          if (contentType != null
              && contentType.startsWith("application/x-www-form-urlencoded"))
            StringUtility.parseStr(env, bb, postArray, false, encoding);
        }
       
        if (postArray.getSize() == 0) {
          // needs to be last or else this function will consume the inputstream
          putRequestMap(env, postArray, files, request, addSlashesToValues, encoding);
        }
      }
     
    } catch (IOException e) {
      env.warning(e);
    } finally {
      try {
        if (is != null)
          is.close();
      } catch (IOException e) {
      }
    }
  }

  private static void readMultipartStream(Env env,
                                          MultipartStream ms,
                                          ArrayValue postArray,
                                          ArrayValue files,
                                          boolean addSlashesToValues,
                                          String encoding)
    throws IOException
  {
    ReadStream is;

    while ((is = ms.openRead()) != null) {
      String attr = (String) ms.getAttribute("content-disposition");

      if (attr == null || ! attr.startsWith("form-data")) {
        // XXX: is this an error?
        continue;
      }

      String name = getAttribute(attr, "name");
      String filename = getAttribute(attr, "filename");

      if (filename == null) {
        byte[] buf = new byte[1];
        int ch, buf_len = 0;

        while ((ch = is.read()) >= 0) {
          if (buf_len >= buf.length) {
            byte[] new_buf = new byte[buf.length * 2];
            System.arraycopy(buf, 0, new_buf, 0, buf.length);
            buf = new_buf;
          }
          buf[buf_len++] = (byte)ch;
        }

        addFormValue(env, postArray, name,
                     env.isUnicodeSemantics() ? new UnicodeBuilderValue(
                         new String(buf, 0, buf_len, encoding)):
                         new StringBuilderValue(buf, 0, buf_len),
                     null, addSlashesToValues, encoding);
      }
      else {
        String tmpName = "";
        long tmpLength = 0;

        // A POST file upload with an empty string as the filename does not
        // create a temp file in the upload directory.

        if (filename.length() > 0) {
          Path tmpPath = env.getUploadDirectory().createTempFile("php", ".tmp");

          env.addRemovePath(tmpPath);

          WriteStream os = tmpPath.openWrite();
          try {
            os.writeStream(is);
          } finally {
            os.close();
          }

          tmpName = tmpPath.getFullPath();
          tmpLength = tmpPath.getLength();
        }

        // php/0865
        //
        // A header like "Content-Type: image/gif" indicates the mime type
        // for an uploaded file.

        String mimeType = getAttribute(attr, "mime-type");
        if (mimeType == null) {
          mimeType = (String) ms.getAttribute("content-type");
        }

        // php/0864
        //
        // mime type is empty string when no file is uploaded.

        if (filename.length() == 0) {
          mimeType = "";
        }

        addFormFile(env,
                    files,
                    name,
                    filename,
                    tmpName,
                    mimeType,
                    tmpLength,
                    addSlashesToValues,
                    encoding);
      }
    }
  }

  private static void addFormFile(Env env,
                                  ArrayValue files,
                                  String name,
                                  String fileName,
                                  String tmpName,
                                  String mimeType,
                                  long fileLength,
                                  boolean addSlashesToValues,
                                  String encoding)
  {
    int p = name.indexOf('[');
    String index = "";
    if (p >= 0) {
      index = name.substring(p);
      name = name.substring(0, p);
    }

    StringValue nameValue = env.createString(name, encoding);
    Value v = files.get(nameValue).toValue();
    ArrayValue entry = null;
    if (v instanceof ArrayValue)
      entry = (ArrayValue) v;

    if (entry == null) {
      entry = new ArrayValueImpl();
      files.put(nameValue, entry);
    }

    int error;

    // php/1667
    long uploadMaxFilesize
      = env.getIniBytes("upload_max_filesize", 2 * 1024 * 1024);

    if (fileName.length() == 0)
      // php/0864
      error = FileModule.UPLOAD_ERR_NO_FILE;
    else if (fileLength > uploadMaxFilesize)
      error = FileModule.UPLOAD_ERR_INI_SIZE;
    else
      error = FileModule.UPLOAD_ERR_OK;

    addFormValue(env, entry, "name" + index, env.createString(fileName, encoding),
                 null, addSlashesToValues, encoding);

    long size;

    if (error != FileModule.UPLOAD_ERR_INI_SIZE) {
      size = fileLength;
    }
    else {
      mimeType = "";
      tmpName = "";
      size = 0;
    }

    if (mimeType != null) {
      addFormValue(env, entry, "type" + index, env.createString(mimeType, encoding),
                   null, addSlashesToValues, encoding);

      entry.put("type", mimeType);
    }

    addFormValue(env, entry, "tmp_name" + index, env.createString(tmpName, encoding),
                 null, addSlashesToValues, encoding);

    addFormValue(env, entry, "error" + index, LongValue.create(error),
                 null, addSlashesToValues, encoding);

    addFormValue(env, entry, "size" + index, LongValue.create(size),
                 null, addSlashesToValues, encoding);

    addFormValue(env, files, name, entry, null, addSlashesToValues, encoding);
  }
 
  public static void addFormValue(Env env,
                                  ArrayValue array,
                                  String key,
                                  String []formValueList,
                                  boolean addSlashesToValues,
                                  String encoding)
  {
    // php/081b
    String formValue = formValueList[formValueList.length - 1];
    Value value;

    if (formValue != null)
      value = env.createString(formValue, encoding);
    else
      value = NullValue.NULL;

    addFormValue(env, array, key,
                 value,
                 formValueList,
                 addSlashesToValues,
                 encoding);
  }

  public static void addFormValue(Env env,
                                  ArrayValue array,
                                  String key,
                                  Value formValue,
                                  String []formValueList,
                                  boolean addSlashesToValues,
                                  String encoding)
  {
    int p = key.indexOf('[');
    int q = key.indexOf(']', p);

    if (p >= 0 && p < q) {
      String index = key;
     
      Value keyValue;
      Value existingValue;

      if (p > 0) {
        key = key.substring(0, p);
       
        key = key.replaceAll("\\.", "_");
       
        keyValue = env.createString(key, encoding);
        existingValue = array.get(keyValue);

        if (existingValue == null || ! existingValue.isset()) {
          existingValue = new ArrayValueImpl();
          array.put(keyValue, existingValue);
        }
        else if (! existingValue.isArray()) {
          //existing is overwritten
          // php/115g
         
          existingValue = new ArrayValueImpl();
          array.put(keyValue, existingValue);
        }

        array = (ArrayValue) existingValue;
      }

      int p1;
      while ((p1 = index.indexOf('[', q)) > 0) {
        key = index.substring(p + 1, q);

        if (key.equals("")) {
          existingValue = new ArrayValueImpl();
          array.put(existingValue);
        }
        else {
          keyValue = env.createString(key, encoding);
          existingValue = array.get(keyValue);

          if (existingValue == null || ! existingValue.isset()) {
            existingValue = new ArrayValueImpl();
            array.put(keyValue, existingValue);
          }
          else if (! existingValue.isArray()) {
            existingValue = new ArrayValueImpl().put(existingValue);
            array.put(keyValue, existingValue);
          }
        }

        array = (ArrayValue) existingValue;

        p = p1;
        q = index.indexOf(']', p);
      }

      if (q > 0)
        index = index.substring(p + 1, q);
      else
        index = index.substring(p + 1);

      if (index.equals("")) {
        if (formValueList != null) {
          for (int i = 0; i < formValueList.length; i++) {
            Value value;

            if (formValueList[i] != null)
              value = env.createString(formValueList[i], encoding);
            else
              value = NullValue.NULL;
           
            put(env, array, null, value, addSlashesToValues);
          }
        }
        else
          array.put(formValue);
      }
      else if ('0' <= index.charAt(0) && index.charAt(0) <= '9')
        put(env, array, LongValue.create(StringValue.toLong(index)), formValue, addSlashesToValues);
      else
        put(env, array, env.createString(index, encoding), formValue, addSlashesToValues);
    }
    else {
      key = key.replaceAll("\\.", "_");
     
      put(env, array, env.createString(key, encoding), formValue, addSlashesToValues);
    }
  }

  private static void put(Env env,
                          ArrayValue array,
                          Value key,
                          Value value,
                          boolean addSlashes)
  {
    if (addSlashes && (value instanceof StringValue)) {
      value = StringModule.addslashes(value.toStringValue(env));
    }

    if (key == null)
      array.put(value);
    else
      array.put(key, value);
  }

  private static String getBoundary(String contentType)
  {
    int i = contentType.indexOf("boundary=");
    if (i < 0)
      return null;

    i += "boundary=".length();

    int length = contentType.length();

    char ch;

    if (length <= i)
      return null;
    else if ((ch = contentType.charAt(i)) == '\'') {
      StringBuilder sb = new StringBuilder();

      for (i++; i < length && (ch = contentType.charAt(i)) != '\''; i++) {
        sb.append(ch);
      }

      return sb.toString();
    }
    else if (ch == '"') {
      StringBuilder sb = new StringBuilder();

      for (i++; i < length && (ch = contentType.charAt(i)) != '"'; i++) {
        sb.append(ch);
      }

      return sb.toString();
    }
    else {
      StringBuilder sb = new StringBuilder();

      for (; i < length && (ch = contentType.charAt(i)) != ' ' && ch != ';'; i++) {
        sb.append(ch);
      }

      return sb.toString();
    }
  }

  private static String getAttribute(String attr, String name)
  {
    if (attr == null)
      return null;

    int length = attr.length();
    int i = attr.indexOf(name);
    if (i < 0)
      return null;

    for (i += name.length(); i < length && attr.charAt(i) != '='; i++) {
    }

    for (i++; i < length && attr.charAt(i) == ' '; i++) {
    }

    StringBuilder value = new StringBuilder();

    if (i < length && attr.charAt(i) == '\'') {
      for (i++; i < length && attr.charAt(i) != '\''; i++)
        value.append(attr.charAt(i));
    }
    else if (i < length && attr.charAt(i) == '"') {
      for (i++; i < length && attr.charAt(i) != '"'; i++)
        value.append(attr.charAt(i));
    }
    else if (i < length) {
      char ch;
      for (; i < length && (ch = attr.charAt(i)) != ' ' && ch != ';'; i++)
        value.append(ch);
    }

    return value.toString();
  }
 
  @SuppressWarnings("unchecked")
  private static void putRequestMap(Env env,
                                    ArrayValue post,
                                    ArrayValue files,
                                    HttpServletRequest request,
                                    boolean addSlashesToValues,
                                    String encoding)
  {
    // this call consumes the inputstream
    Map<String,String[]> map = (Map<String,String[]>)request.getParameterMap();

    if (map == null)
      return;
   
    for (Map.Entry<String,String[]> entry : map.entrySet()) {
      String key = entry.getKey();

      int len = key.length();

      if (len < 10 || ! key.endsWith(".filename"))
        continue;

      String name = key.substring(0, len - 9);

      String []fileNames = request.getParameterValues(name + ".filename");
      String []tmpNames = request.getParameterValues(name + ".file");
      String []mimeTypes = request.getParameterValues(name + ".content-type");

      for (int i = 0; i < fileNames.length; i++) {
        long fileLength = new FilePath(tmpNames[i]).getLength();

        addFormFile(env, files, name, fileNames[i], tmpNames[i], mimeTypes[i], fileLength, addSlashesToValues, encoding);
      }
    }

    ArrayList<String> keys = new ArrayList<String>();

    keys.addAll((Set<String>)request.getParameterMap().keySet());

    Collections.sort(keys);

    for (String key : keys) {  
      String []value = request.getParameterValues(key);
     
      Post.addFormValue(env, post, key, value, addSlashesToValues, encoding);
    }
  }
}
TOP

Related Classes of com.caucho.quercus.env.Post

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.