public void send(Object userData) throws MethodNotSupportedException {
    // TODO consider using task manager
    final TiHTTPClient me = this;
    double totalLength = 0;
    needMultipart = false;

    if (userData != null) {
      if (userData instanceof TiDict) {
        TiDict data = (TiDict) userData;

        // first time through check if we need multipart for POST
        for (String key : data.keySet()) {
          Object value = data.get(key);
          if (value instanceof TiBaseFile || value instanceof TiBlob) {
            needMultipart = true;
          }
        }

        for (String key : data.keySet()) {
          Object value = data.get(key);

          if (method.equals("POST") || method.equals("PUT")) {
            if (value instanceof TiBaseFile || value instanceof TiBlob) {
              totalLength += addTitaniumFileAsPostData(key, value);
            } else {
              String str = TiConvert.toString(value);
              addPostData(key, str);
              totalLength += str.length();
            }
          } else if (method.equals("GET")) {
            uri = uri.buildUpon().appendQueryParameter(key, TiConvert.toString(value)).build();
          }
        }
      } else {
        addStringData(TiConvert.toString(userData));
      }
    }

    request = new DefaultHttpRequestFactory().newHttpRequest(method, uri.toString());
    for (String header : headers.keySet()) {
      request.setHeader(header, headers.get(header));
    }

    clientThread =
        new Thread(
            new ClientRunnable(totalLength),
            "TiHttpClient-" + httpClientThreadCounter.incrementAndGet());
    clientThread.setPriority(Thread.MIN_PRIORITY);
    clientThread.start();
    if (DBG) {
      Log.d(LCAT, "Leaving send()");
    }
  }
  @SuppressWarnings("serial")
  public static Object fromNative(Object value, KrollContext kroll) {
    Object o = value;

    if (DBG) {
      if (value != null) {
        Log.d(LCAT, "Incoming type is " + value.getClass().getCanonicalName());
      }
    }
    if (value == null
        || value instanceof String
        || value instanceof Number
        || value instanceof Boolean
        || value instanceof Scriptable
        || value instanceof Function) {
      o = Context.javaToJS(value, kroll.getScope());
    } else if (value instanceof TiDict) {
      TiDict d = (TiDict) value;
      ScriptableObject so =
          new ScriptableObject(
              kroll.getScope(), ScriptableObject.getObjectPrototype(kroll.getScope())) {
            @Override
            public String getClassName() {
              return "Object";
            }

            public String toString() {
              StringBuilder sb = new StringBuilder();
              sb.append("{ ");

              Object[] ids = (Object[]) getIds();
              String sep = "";

              if (ids != null) {
                for (Object id : ids) {
                  sb.append(" '").append(id).append("' : ");
                  Object o = get(id.toString(), this);
                  if (o == null) {
                    sb.append("null");
                  } else if (o instanceof String) {
                    sb.append(" '").append((String) o).append("' ");
                  } else if (o instanceof Number) {
                    sb.append(o);
                  } else if (o instanceof ScriptableObject) {
                    sb.append(" {").append(o).append("} ");
                  } else {
                    sb.append(o);
                  }

                  sb.append("sep");
                  sep = ",";
                }
              }

              sb.append(" }");

              return sb.toString();
            }
          };
      for (String key : d.keySet()) {
        so.put(key, so, fromNative(d.get(key), kroll));
      }
      o = so;
    } else if (value instanceof Date) {
      Date date = (Date) value;
      o =
          Context.getCurrentContext()
              .newObject(kroll.getScope(), "Date", new Object[] {date.getTime()});
    } else if (value.getClass().isArray()) {
      int length = Array.getLength(value);
      Object[] jsArray = new Object[length];
      for (int i = 0; i < length; i++) {
        jsArray[i] = fromNative(Array.get(value, i), kroll);
      }

      o = Context.getCurrentContext().newObject(kroll.getScope(), "Array", jsArray);
    } else {
      o = new KrollObject(kroll, value);
    }

    return o;
  }