예제 #1
1
  private static HttpResponse addEtag(
      HttpRequest nettyRequest, HttpResponse httpResponse, File file) {
    if (Play.mode == Play.Mode.DEV) {
      httpResponse.setHeader(CACHE_CONTROL, "no-cache");
    } else {
      String maxAge = Play.configuration.getProperty("http.cacheControl", "3600");
      if (maxAge.equals("0")) {
        httpResponse.setHeader(CACHE_CONTROL, "no-cache");
      } else {
        httpResponse.setHeader(CACHE_CONTROL, "max-age=" + maxAge);
      }
    }
    boolean useEtag = Play.configuration.getProperty("http.useETag", "true").equals("true");
    long last = file.lastModified();
    final String etag = "\"" + last + "-" + file.hashCode() + "\"";
    if (!isModified(etag, last, nettyRequest)) {
      if (nettyRequest.getMethod().equals(HttpMethod.GET)) {
        httpResponse.setStatus(HttpResponseStatus.NOT_MODIFIED);
      }
      if (useEtag) {
        httpResponse.setHeader(ETAG, etag);
      }

    } else {
      httpResponse.setHeader(LAST_MODIFIED, Utils.getHttpDateFormatter().format(new Date(last)));
      if (useEtag) {
        httpResponse.setHeader(ETAG, etag);
      }
    }
    return httpResponse;
  }
예제 #2
0
 public static Object invokeControllerMethod(Method method, Object[] forceArgs) throws Exception {
   if (Modifier.isStatic(method.getModifiers())
       && !method.getDeclaringClass().getName().matches("^controllers\\..*\\$class$")) {
     return invoke(
         method, null, forceArgs == null ? getActionMethodArgs(method, null) : forceArgs);
   } else if (Modifier.isStatic(method.getModifiers())) {
     Object[] args = getActionMethodArgs(method, null);
     args[0] = Http.Request.current().controllerClass.getDeclaredField("MODULE$").get(null);
     return invoke(method, null, args);
   } else {
     Object instance = null;
     try {
       instance = method.getDeclaringClass().getDeclaredField("MODULE$").get(null);
     } catch (Exception e) {
       Annotation[] annotations = method.getDeclaredAnnotations();
       String annotation = Utils.getSimpleNames(annotations);
       if (!StringUtils.isEmpty(annotation)) {
         throw new UnexpectedException(
             "Method public static void "
                 + method.getName()
                 + "() annotated with "
                 + annotation
                 + " in class "
                 + method.getDeclaringClass().getName()
                 + " is not static.");
       }
       // TODO: Find a better error report
       throw new ActionNotFoundException(Http.Request.current().action, e);
     }
     return invoke(
         method, instance, forceArgs == null ? getActionMethodArgs(method, instance) : forceArgs);
   }
 }
예제 #3
0
  public static boolean isModified(String etag, long last, HttpRequest nettyRequest) {

    if (nettyRequest.containsHeader(IF_NONE_MATCH)) {
      final String browserEtag = nettyRequest.getHeader(IF_NONE_MATCH);
      if (browserEtag.equals(etag)) {
        return false;
      }
      return true;
    }

    if (nettyRequest.containsHeader(IF_MODIFIED_SINCE)) {
      final String ifModifiedSince = nettyRequest.getHeader(IF_MODIFIED_SINCE);

      if (!StringUtils.isEmpty(ifModifiedSince)) {
        try {
          Date browserDate = Utils.getHttpDateFormatter().parse(ifModifiedSince);
          if (browserDate.getTime() >= last) {
            return false;
          }
        } catch (ParseException ex) {
          Logger.warn("Can't parse HTTP date", ex);
        }
        return true;
      }
    }
    return true;
  }
예제 #4
0
 private static boolean isValidTimeStamp(long last, String dateString) {
   try {
     long browserDate = Utils.getHttpDateFormatter().parse(dateString).getTime();
     return browserDate >= last;
   } catch (ParseException e) {
     Logger.error("Can't parse date", e);
     return false;
   }
 }
예제 #5
0
  public void serveStatic(
      HttpServletResponse servletResponse,
      HttpServletRequest servletRequest,
      RenderStatic renderStatic)
      throws IOException {

    VirtualFile file = Play.getVirtualFile(renderStatic.file);
    if (file == null || file.isDirectory() || !file.exists()) {
      serve404(
          servletRequest,
          servletResponse,
          new NotFound("The file " + renderStatic.file + " does not exist"));
    } else {
      servletResponse.setContentType(MimeTypes.getContentType(file.getName()));
      boolean raw = false;
      for (PlayPlugin plugin : Play.plugins) {
        if (plugin.serveStatic(file, Request.current(), Response.current())) {
          raw = true;
          break;
        }
      }
      if (raw) {
        copyResponse(Request.current(), Response.current(), servletRequest, servletResponse);
      } else {
        if (Play.mode == Play.Mode.DEV) {
          servletResponse.setHeader("Cache-Control", "no-cache");
          servletResponse.setHeader("Content-Length", String.valueOf(file.length()));
          if (!servletRequest.getMethod().equals("HEAD")) {
            copyStream(servletResponse, file.inputstream());
          } else {
            copyStream(servletResponse, new ByteArrayInputStream(new byte[0]));
          }
        } else {
          long last = file.lastModified();
          String etag = "\"" + last + "-" + file.hashCode() + "\"";
          if (!isModified(etag, last, servletRequest)) {
            servletResponse.setHeader("Etag", etag);
            servletResponse.setStatus(304);
          } else {
            servletResponse.setHeader(
                "Last-Modified", Utils.getHttpDateFormatter().format(new Date(last)));
            servletResponse.setHeader(
                "Cache-Control",
                "max-age=" + Play.configuration.getProperty("http.cacheControl", "3600"));
            servletResponse.setHeader("Etag", etag);
            copyStream(servletResponse, file.inputstream());
          }
        }
      }
    }
  }
예제 #6
0
  public static Object[] getActionMethodArgs(Method method, Object o) throws Exception {
    String[] paramsNames = Java.parameterNames(method);
    if (paramsNames == null && method.getParameterTypes().length > 0) {
      throw new UnexpectedException("Parameter names not found for method " + method);
    }

    // Check if we have already performed the bind operation
    Object[] rArgs = CachedBoundActionMethodArgs.current().retrieveActionMethodArgs(method);
    if (rArgs != null) {
      // We have already performed the binding-operation for this method
      // in this request.
      return rArgs;
    }

    rArgs = new Object[method.getParameterTypes().length];
    for (int i = 0; i < method.getParameterTypes().length; i++) {

      Class<?> type = method.getParameterTypes()[i];
      Map<String, String[]> params = new HashMap<String, String[]>();

      // In case of simple params, we don't want to parse the body.
      if (type.equals(String.class) || Number.class.isAssignableFrom(type) || type.isPrimitive()) {
        params.put(paramsNames[i], Scope.Params.current().getAll(paramsNames[i]));
      } else {
        params.putAll(Scope.Params.current().all());
      }
      Logger.trace(
          "getActionMethodArgs name ["
              + paramsNames[i]
              + "] annotation ["
              + Utils.join(method.getParameterAnnotations()[i], " ")
              + "]");

      RootParamNode root = ParamNode.convert(params);
      rArgs[i] =
          Binder.bind(
              root,
              paramsNames[i],
              method.getParameterTypes()[i],
              method.getGenericParameterTypes()[i],
              method.getParameterAnnotations()[i],
              new Binder.MethodAndParamInfo(o, method, i + 1));
    }

    CachedBoundActionMethodArgs.current().storeActionMethodArgs(method, rArgs);
    return rArgs;
  }
예제 #7
0
 public static boolean isModified(String etag, long last, HttpServletRequest request) {
   if (!(request.getHeader("If-None-Match") == null
       && request.getHeaders("If-Modified-Since") == null)) {
     return true;
   } else {
     String browserEtag = request.getHeader("If-None-Match");
     if (!browserEtag.equals(etag)) {
       return true;
     } else {
       try {
         Date browserDate =
             Utils.getHttpDateFormatter().parse(request.getHeader("If-Modified-Since"));
         if (browserDate.getTime() >= last) {
           return false;
         }
       } catch (ParseException ex) {
         Logger.error("Can't parse date", ex);
       }
       return true;
     }
   }
 }
예제 #8
0
    /**
     * Check if the parts of a HTTP request equal this Route.
     *
     * @param method GET/POST/etc.
     * @param path Part after domain and before query-string. Starts with a "/".
     * @param accept Format, e.g. html.
     * @param domain The domain (host without port).
     * @return ???
     */
    public Map<String, String> matches(String method, String path, String accept, String domain) {
      // Normalize
      if (path.equals(Play.ctxPath)) {
        path = path + "/";
      }
      // If method is HEAD and we have a GET
      if (method == null
          || this.method.equals("*")
          || method.equalsIgnoreCase(this.method)
          || (method.equalsIgnoreCase("head") && ("get").equalsIgnoreCase(this.method))) {

        Matcher matcher = pattern.matcher(path);

        boolean hostMatches = (domain == null);
        if (domain != null) {

          Matcher hostMatcher = hostPattern.matcher(domain);
          hostMatches = hostMatcher.matches();
        }
        // Extract the host variable
        if (matcher.matches() && contains(accept) && hostMatches) {
          // 404
          if (action.equals("404")) {
            throw new NotFound(method, path);
          }
          // Static dir
          if (staticDir != null) {
            String resource = null;
            if (!staticFile) {
              resource = matcher.group("resource");
            }
            try {
              String root = new File(staticDir).getCanonicalPath();
              String urlDecodedResource = Utils.urlDecodePath(resource);
              String childResourceName = staticDir + (staticFile ? "" : "/" + urlDecodedResource);
              String child = new File(childResourceName).getCanonicalPath();
              if (child.startsWith(root)) {
                throw new RenderStatic(childResourceName);
              }
            } catch (IOException e) {
            }
            throw new NotFound(resource);
          } else {
            Map<String, String> localArgs = new HashMap<String, String>();
            for (Arg arg : args) {
              // FIXME: Careful with the arguments that are not matching as they are part of the
              // hostname
              // Defaultvalue indicates it is a one of these urls. This is a trick and should be
              // changed.
              if (arg.defaultValue == null) {
                localArgs.put(arg.name, Utils.urlDecodePath(matcher.group(arg.name)));
              }
            }
            if (hostArg != null && domain != null) {
              // Parse the hostname and get only the part we are interested in
              String routeValue = hostArg.defaultValue.replaceAll("\\{.*}", "");
              domain = domain.replace(routeValue, "");
              localArgs.put(hostArg.name, domain);
            }
            localArgs.putAll(staticArgs);
            return localArgs;
          }
        }
      }
      return null;
    }
예제 #9
0
  @SuppressWarnings("unchecked")
  static Object bindInternal(
      String name,
      Class clazz,
      Type type,
      Annotation[] annotations,
      Map<String, String[]> params,
      String suffix,
      String[] profiles) {
    try {
      Logger.trace("bindInternal: name [" + name + "] suffix [" + suffix + "]");

      String[] value = params.get(name + suffix);
      Logger.trace("bindInternal: value [" + value + "]");
      Logger.trace("bindInternal: profile [" + Utils.join(profiles, ",") + "]");
      // Let see if we have a BindAs annotation and a separator. If so, we need to split the values
      // Look up for the BindAs annotation. Extract the profile if there is any.
      // TODO: Move me somewhere else?
      if (annotations != null) {
        for (Annotation annotation : annotations) {
          if ((clazz.isArray() || Collection.class.isAssignableFrom(clazz))
              && value != null
              && value.length > 0
              && annotation.annotationType().equals(As.class)) {
            As as = ((As) annotation);
            final String separator = as.value()[0];
            value = value[0].split(separator);
          }
          if (annotation.annotationType().equals(NoBinding.class)) {
            NoBinding bind = ((NoBinding) annotation);
            String[] localUnbindProfiles = bind.value();
            Logger.trace(
                "bindInternal: localUnbindProfiles [" + Utils.join(localUnbindProfiles, ",") + "]");

            if (localUnbindProfiles != null && contains(profiles, localUnbindProfiles)) {
              return NO_BINDING;
            }
          }
        }
      }

      // Arrays types
      // The array condition is not so nice... We should find another way of doing this....
      if (clazz.isArray()
          && (clazz != byte[].class
              && clazz != byte[][].class
              && clazz != File[].class
              && clazz != Upload[].class)) {
        if (value == null) {
          value = params.get(name + suffix + "[]");
        }
        if (value == null) {
          return MISSING;
        }
        Object r = Array.newInstance(clazz.getComponentType(), value.length);
        for (int i = 0; i <= value.length; i++) {
          try {
            Array.set(r, i, directBind(name, annotations, value[i], clazz.getComponentType()));
          } catch (Exception e) {
            // ?? One item was bad
          }
        }
        return r;
      }
      // Enums
      if (Enum.class.isAssignableFrom(clazz)) {
        if (value == null || value.length == 0) {
          return MISSING;
        } else if (StringUtils.isEmpty(value[0])) {
          return null;
        }
        return Enum.valueOf(clazz, value[0]);
      }
      // Map
      if (Map.class.isAssignableFrom(clazz)) {
        Class keyClass = String.class;
        Class valueClass = String.class;
        if (type instanceof ParameterizedType) {
          keyClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0];
          valueClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[1];
        }

        // Special case Map<String, String>
        // Multivalues composite params are binded to a Map<String, String>
        // see http://play.lighthouseapp.com/projects/57987/tickets/443
        if (keyClass == String.class && valueClass == String.class && isComposite(name, params)) {
          Map<String, String> stringMap = Utils.filterParams(params, name);
          if (stringMap.size() > 0) return stringMap;
        }

        // Search for all params
        Map<Object, Object> r = new HashMap<Object, Object>();
        for (String param : params.keySet()) {
          Pattern p = Pattern.compile("^" + name + suffix + "\\[([^\\]]+)\\](.*)$");
          Matcher m = p.matcher(param);
          if (m.matches()) {
            String key = m.group(1);
            value = params.get(param);
            Map<String, String[]> tP = new HashMap<String, String[]>();
            tP.put("key", new String[] {key});
            Object oKey = bindInternal("key", keyClass, keyClass, annotations, tP, "", value);
            if (oKey != MISSING) {
              if (isComposite(name + suffix + "[" + key + "]", params)) {
                BeanWrapper beanWrapper = getBeanWrapper(valueClass);
                Object oValue =
                    beanWrapper.bind(
                        "", type, params, name + suffix + "[" + key + "]", annotations);
                r.put(oKey, oValue);
              } else {
                tP = new HashMap<String, String[]>();
                tP.put("value", params.get(name + suffix + "[" + key + "]"));
                Object oValue =
                    bindInternal("value", valueClass, valueClass, annotations, tP, "", value);
                if (oValue != MISSING) {
                  r.put(oKey, oValue);
                } else {
                  r.put(oKey, null);
                }
              }
            }
          }
        }
        return r;
      }
      // Collections types
      if (Collection.class.isAssignableFrom(clazz)) {
        if (clazz.isInterface()) {
          if (clazz.equals(List.class)) {
            clazz = ArrayList.class;
          }
          if (clazz.equals(Set.class)) {
            clazz = HashSet.class;
          }
          if (clazz.equals(SortedSet.class)) {
            clazz = TreeSet.class;
          }
        }
        Collection r = (Collection) clazz.newInstance();
        Class componentClass = String.class;
        if (type instanceof ParameterizedType) {
          componentClass = (Class) ((ParameterizedType) type).getActualTypeArguments()[0];
        }
        // Create a an array of the component class
        if (value != null) {
          Object customArray = Array.newInstance(componentClass, value.length);
          // custom types
          for (Class<?> c : supportedTypes.keySet()) {
            if (c.isAssignableFrom(customArray.getClass())) {
              Object[] ar =
                  (Object[])
                      supportedTypes
                          .get(c)
                          .bind("value", annotations, name, customArray.getClass(), null);
              List l = Arrays.asList(ar);
              if (clazz.equals(HashSet.class)) {
                return new HashSet(l);
              } else if (clazz.equals(TreeSet.class)) {
                return new TreeSet(l);
              }
              return l;
            }
          }
        }
        if (value == null) {
          value = params.get(name + suffix + "[]");
          if (value == null && r instanceof List) {
            for (String param : params.keySet()) {
              Pattern p = Pattern.compile("^" + escape(name + suffix) + "\\[([0-9]+)\\](.*)$");
              Matcher m = p.matcher(param);
              if (m.matches()) {
                int key = Integer.parseInt(m.group(1));
                while (((List<?>) r).size() <= key) {
                  ((List<?>) r).add(null);
                }
                if (isComposite(name + suffix + "[" + key + "]", params)) {
                  BeanWrapper beanWrapper = getBeanWrapper(componentClass);
                  Object oValue =
                      beanWrapper.bind(
                          "", type, params, name + suffix + "[" + key + "]", annotations);
                  ((List) r).set(key, oValue);
                } else {
                  Map<String, String[]> tP = new HashMap<String, String[]>();
                  tP.put("value", params.get(name + suffix + "[" + key + "]"));
                  Object oValue =
                      bindInternal(
                          "value", componentClass, componentClass, annotations, tP, "", value);
                  if (oValue != MISSING) {
                    ((List) r).set(key, oValue);
                  }
                }
              }
            }
            return r.isEmpty() ? MISSING : r;
          }
        }
        if (value == null) {
          return MISSING;
        }
        for (String v : value) {
          try {
            r.add(directBind(name, annotations, v, componentClass));
          } catch (Exception e) {
            // ?? One item was bad
            Logger.debug(e, "error:");
          }
        }
        return r;
      }

      // Assume a Bean if isComposite
      Logger.trace(
          "bindInternal: class ["
              + clazz
              + "] name ["
              + name
              + "] annotation ["
              + Utils.join(annotations, " ")
              + "] isComposite ["
              + isComposite(name + suffix, params)
              + "]");
      if (isComposite(name + suffix, params)) {
        BeanWrapper beanWrapper = getBeanWrapper(clazz);
        return beanWrapper.bind(name, type, params, suffix, annotations);
      }

      // Simple types
      if (value == null || value.length == 0) {
        return MISSING;
      }

      return directBind(name, annotations, value[0], clazz, type);
    } catch (Exception e) {
      Validation.addError(name + suffix, "validation.invalid");
      return MISSING;
    }
  }
예제 #10
0
  @SuppressWarnings("unchecked")
  public static Object directBind(
      String name, Annotation[] annotations, String value, Class<?> clazz, Type type)
      throws Exception {
    Logger.trace(
        "directBind: value ["
            + value
            + "] annotation ["
            + Utils.join(annotations, " ")
            + "] Class ["
            + clazz
            + "]");

    boolean nullOrEmpty = value == null || value.trim().length() == 0;

    if (annotations != null) {
      for (Annotation annotation : annotations) {
        if (annotation.annotationType().equals(As.class)) {
          Class<? extends TypeBinder<?>> toInstanciate = ((As) annotation).binder();
          if (!(toInstanciate.equals(As.DEFAULT.class))) {
            // Instantiate the binder
            TypeBinder<?> myInstance = toInstanciate.newInstance();
            return myInstance.bind(name, annotations, value, clazz, type);
          }
        }
      }
    }

    // custom types
    for (Class<?> c : supportedTypes.keySet()) {
      Logger.trace("directBind: value [" + value + "] c [" + c + "] Class [" + clazz + "]");
      if (c.isAssignableFrom(clazz)) {
        Logger.trace("directBind: isAssignableFrom is true");
        return supportedTypes.get(c).bind(name, annotations, value, clazz, type);
      }
    }

    // application custom types
    for (Class<TypeBinder<?>> c : Play.classloader.getAssignableClasses(TypeBinder.class)) {
      if (c.isAnnotationPresent(Global.class)) {
        Class<?> forType =
            (Class) ((ParameterizedType) c.getGenericInterfaces()[0]).getActualTypeArguments()[0];
        if (forType.isAssignableFrom(clazz)) {
          return c.newInstance().bind(name, annotations, value, clazz, type);
        }
      }
    }

    // raw String
    if (clazz.equals(String.class)) {
      return value;
    }

    // Enums
    if (Enum.class.isAssignableFrom(clazz)) {
      if (nullOrEmpty) {
        return null;
      }
      return Enum.valueOf((Class<Enum>) clazz, value);
    }

    // int or Integer binding
    if (clazz.getName().equals("int") || clazz.equals(Integer.class)) {
      if (nullOrEmpty) {
        return clazz.isPrimitive() ? 0 : null;
      }

      return Integer.parseInt(value.contains(".") ? value.substring(0, value.indexOf(".")) : value);
    }

    // long or Long binding
    if (clazz.getName().equals("long") || clazz.equals(Long.class)) {
      if (nullOrEmpty) {
        return clazz.isPrimitive() ? 0l : null;
      }

      return Long.parseLong(value.contains(".") ? value.substring(0, value.indexOf(".")) : value);
    }

    // byte or Byte binding
    if (clazz.getName().equals("byte") || clazz.equals(Byte.class)) {
      if (nullOrEmpty) {
        return clazz.isPrimitive() ? (byte) 0 : null;
      }

      return Byte.parseByte(value.contains(".") ? value.substring(0, value.indexOf(".")) : value);
    }

    // short or Short binding
    if (clazz.getName().equals("short") || clazz.equals(Short.class)) {
      if (nullOrEmpty) {
        return clazz.isPrimitive() ? (short) 0 : null;
      }

      return Short.parseShort(value.contains(".") ? value.substring(0, value.indexOf(".")) : value);
    }

    // float or Float binding
    if (clazz.getName().equals("float") || clazz.equals(Float.class)) {
      if (nullOrEmpty) {
        return clazz.isPrimitive() ? 0f : null;
      }

      return Float.parseFloat(value);
    }

    // double or Double binding
    if (clazz.getName().equals("double") || clazz.equals(Double.class)) {
      if (nullOrEmpty) {
        return clazz.isPrimitive() ? 0d : null;
      }

      return Double.parseDouble(value);
    }

    // BigDecimal binding
    if (clazz.equals(BigDecimal.class)) {
      if (nullOrEmpty) {
        return null;
      }

      return new BigDecimal(value);
    }

    // boolean or Boolean binding
    if (clazz.getName().equals("boolean") || clazz.equals(Boolean.class)) {
      if (nullOrEmpty) {
        return clazz.isPrimitive() ? false : null;
      }

      if (value.equals("1")
          || value.toLowerCase().equals("on")
          || value.toLowerCase().equals("yes")) {
        return true;
      }

      return Boolean.parseBoolean(value);
    }

    return null;
  }
예제 #11
0
  public static Object bind(
      String name,
      Class<?> clazz,
      Type type,
      Annotation[] annotations,
      Map<String, String[]> params,
      Object o,
      Method method,
      int parameterIndex) {
    Logger.trace("bind: name [" + name + "] annotation [" + Utils.join(annotations, " ") + "] ");

    Object result = null;
    // Let a chance to plugins to bind this object
    for (PlayPlugin plugin : Play.plugins) {
      result = plugin.bind(name, clazz, type, annotations, params);
      if (result != null) {
        return result;
      }
    }
    String[] profiles = null;
    if (annotations != null) {
      for (Annotation annotation : annotations) {
        if (annotation.annotationType().equals(As.class)) {
          As as = ((As) annotation);
          profiles = as.value();
        }
        if (annotation.annotationType().equals(NoBinding.class)) {
          NoBinding bind = ((NoBinding) annotation);
          profiles = bind.value();
        }
      }
    }
    result = bindInternal(name, clazz, type, annotations, params, "", profiles);

    if (result == MISSING) {
      // Try the scala default
      if (o != null && parameterIndex > 0) {
        try {
          Method defaultMethod =
              method
                  .getDeclaringClass()
                  .getDeclaredMethod(method.getName() + "$default$" + parameterIndex);
          return defaultMethod.invoke(o);
        } catch (NoSuchMethodException e) {
          //
        } catch (Exception e) {
          throw new UnexpectedException(e);
        }
      }
      if (clazz.equals(boolean.class)) {
        return false;
      }
      if (clazz.equals(int.class)) {
        return 0;
      }
      if (clazz.equals(long.class)) {
        return 0;
      }
      if (clazz.equals(double.class)) {
        return 0;
      }
      if (clazz.equals(short.class)) {
        return 0;
      }
      if (clazz.equals(byte.class)) {
        return 0;
      }
      if (clazz.equals(char.class)) {
        return ' ';
      }
      return null;
    }
    return result;
  }