protected void addCorsHeaders(
      ServerHttpRequest request, ServerHttpResponse response, HttpMethod... httpMethods) {

    String origin = request.getHeaders().getFirst("origin");
    origin = ((origin == null) || origin.equals("null")) ? "*" : origin;

    response.getHeaders().add("Access-Control-Allow-Origin", origin);
    response.getHeaders().add("Access-Control-Allow-Credentials", "true");

    List<String> accessControllerHeaders =
        request.getHeaders().get("Access-Control-Request-Headers");
    if (accessControllerHeaders != null) {
      for (String header : accessControllerHeaders) {
        response.getHeaders().add("Access-Control-Allow-Headers", header);
      }
    }

    if (!ObjectUtils.isEmpty(httpMethods)) {
      response
          .getHeaders()
          .add(
              "Access-Control-Allow-Methods",
              StringUtils.arrayToDelimitedString(httpMethods, ", "));
      response.getHeaders().add("Access-Control-Max-Age", String.valueOf(ONE_YEAR));
    }
  }
        @Override
        public void handle(ServerHttpRequest request, ServerHttpResponse response)
            throws IOException {

          if (HttpMethod.GET.equals(request.getMethod())) {

            response
                .getHeaders()
                .setContentType(new MediaType("application", "json", Charset.forName("UTF-8")));

            addCorsHeaders(request, response);
            addNoCacheHeaders(response);

            String content =
                String.format(
                    INFO_CONTENT,
                    random.nextInt(),
                    isJsessionIdCookieRequired(),
                    isWebSocketEnabled());
            response.getBody().write(content.getBytes());
          } else if (HttpMethod.OPTIONS.equals(request.getMethod())) {

            response.setStatusCode(HttpStatus.NO_CONTENT);

            addCorsHeaders(request, response, HttpMethod.OPTIONS, HttpMethod.GET);
            addCacheHeaders(response);
          } else {
            sendMethodNotAllowed(response, Arrays.asList(HttpMethod.OPTIONS, HttpMethod.GET));
          }
        }
        @Override
        public void handle(ServerHttpRequest request, ServerHttpResponse response)
            throws IOException {

          if (!HttpMethod.GET.equals(request.getMethod())) {
            sendMethodNotAllowed(response, Arrays.asList(HttpMethod.GET));
            return;
          }

          String content = String.format(IFRAME_CONTENT, getSockJsClientLibraryUrl());
          byte[] contentBytes = content.getBytes(Charset.forName("UTF-8"));
          StringBuilder builder = new StringBuilder("\"0");
          DigestUtils.appendMd5DigestAsHex(contentBytes, builder);
          builder.append('"');
          String etagValue = builder.toString();

          List<String> ifNoneMatch = request.getHeaders().getIfNoneMatch();
          if (!CollectionUtils.isEmpty(ifNoneMatch) && ifNoneMatch.get(0).equals(etagValue)) {
            response.setStatusCode(HttpStatus.NOT_MODIFIED);
            return;
          }

          response
              .getHeaders()
              .setContentType(new MediaType("text", "html", Charset.forName("UTF-8")));
          response.getHeaders().setContentLength(contentBytes.length);

          addCacheHeaders(response);
          response.getHeaders().setETag(etagValue);
          response.getBody().write(contentBytes);
        }
  @Override
  public final boolean doHandshake(
      ServerHttpRequest request,
      ServerHttpResponse response,
      WebSocketHandler wsHandler,
      Map<String, Object> attributes)
      throws HandshakeFailureException {

    if (logger.isDebugEnabled()) {
      logger.debug(
          "Initiating handshake for " + request.getURI() + ", headers=" + request.getHeaders());
    }

    try {
      if (!HttpMethod.GET.equals(request.getMethod())) {
        response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
        response.getHeaders().setAllow(Collections.singleton(HttpMethod.GET));
        logger.debug("Only HTTP GET is allowed, current method is " + request.getMethod());
        return false;
      }
      if (!"WebSocket".equalsIgnoreCase(request.getHeaders().getUpgrade())) {
        handleInvalidUpgradeHeader(request, response);
        return false;
      }
      if (!request.getHeaders().getConnection().contains("Upgrade")
          && !request.getHeaders().getConnection().contains("upgrade")) {
        handleInvalidConnectHeader(request, response);
        return false;
      }
      if (!isWebSocketVersionSupported(request)) {
        handleWebSocketVersionNotSupported(request, response);
        return false;
      }
      if (!isValidOrigin(request)) {
        response.setStatusCode(HttpStatus.FORBIDDEN);
        return false;
      }
      String wsKey = request.getHeaders().getSecWebSocketKey();
      if (wsKey == null) {
        logger.debug("Missing \"Sec-WebSocket-Key\" header");
        response.setStatusCode(HttpStatus.BAD_REQUEST);
        return false;
      }
    } catch (IOException ex) {
      throw new HandshakeFailureException(
          "Response update failed during upgrade to WebSocket, uri=" + request.getURI(), ex);
    }

    String subProtocol = selectProtocol(request.getHeaders().getSecWebSocketProtocol());

    if (logger.isDebugEnabled()) {
      logger.debug("Upgrading request, sub-protocol=" + subProtocol);
    }

    this.requestUpgradeStrategy.upgrade(request, response, subProtocol, wsHandler, attributes);

    return true;
  }
 protected void handleWebSocketVersionNotSupported(
     ServerHttpRequest request, ServerHttpResponse response) {
   logger.debug(
       "WebSocket version not supported " + request.getHeaders().get("Sec-WebSocket-Version"));
   response.setStatusCode(HttpStatus.UPGRADE_REQUIRED);
   response
       .getHeaders()
       .setSecWebSocketVersion(StringUtils.arrayToCommaDelimitedString(getSupportedVerions()));
 }
  @Override
  protected void handleRequestInternal(
      ServerHttpRequest request, ServerHttpResponse response, boolean initialRequest)
      throws IOException {

    byte[] prelude = getPrelude(request);
    Assert.notNull(prelude);
    response.getBody().write(prelude);
    response.flush();

    if (initialRequest) {
      writeFrame(SockJsFrame.openFrame());
    }
    flushCache();
  }
  @Override
  protected void handleRawWebSocketRequest(
      ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler)
      throws IOException {

    TransportHandler transportHandler = this.handlers.get(TransportType.WEBSOCKET);
    if (!(transportHandler instanceof HandshakeHandler)) {
      logger.error("No handler configured for raw WebSocket messages");
      response.setStatusCode(HttpStatus.NOT_FOUND);
      return;
    }

    HandshakeInterceptorChain chain = new HandshakeInterceptorChain(this.interceptors, handler);
    HandshakeFailureException failure = null;

    try {
      Map<String, Object> attributes = new HashMap<String, Object>();
      if (!chain.applyBeforeHandshake(request, response, attributes)) {
        return;
      }
      ((HandshakeHandler) transportHandler).doHandshake(request, response, handler, attributes);
      chain.applyAfterHandshake(request, response, null);
    } catch (HandshakeFailureException ex) {
      failure = ex;
    } catch (Throwable ex) {
      failure =
          new HandshakeFailureException("Uncaught failure for request " + request.getURI(), ex);
    } finally {
      if (failure != null) {
        chain.applyAfterHandshake(request, response, failure);
        throw failure;
      }
    }
  }
  @RequestMapping(method = RequestMethod.POST)
  public ModelAndView update(
      @Valid SearchElementEntity elementDefinition,
      BindingResult bindingResult,
      HttpServletRequest httpServletRequest,
      ServerHttpResponse response) {
    LOGGER.info(
        "Creating an filed element: "
            + elementDefinition.getClazz().getSimpleName()
            + " for preset: "
            + elementDefinition.getPreset().getSlug());

    ModelAndView model = new ModelAndView("admin/SearchElementDefinition/updateForm");

    if (bindingResult.hasErrors()) {
      LOGGER.error("Bindding has error...");
      for (ObjectError error : bindingResult.getAllErrors()) {
        LOGGER.error("Error: " + error.getDefaultMessage());
      }
      response.setStatusCode(HttpStatus.PRECONDITION_FAILED);
      return model;
    }
    try {
      elementDefinition = repository.save(elementDefinition);
    } catch (Exception e) {
      LOGGER.error("Could not save elementDefinition", e);
    }
    model.addObject("searchElementDefinition", elementDefinition);
    return model;
  }
  @Override
  public void handleReturnValue(
      Object returnValue,
      MethodParameter returnType,
      ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest)
      throws Exception {

    if (returnValue == null) {
      mavContainer.setRequestHandled(true);
      return;
    }

    HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
    ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);

    if (ResponseEntity.class.isAssignableFrom(returnValue.getClass())) {
      ResponseEntity<?> responseEntity = (ResponseEntity<?>) returnValue;
      outputMessage.setStatusCode(responseEntity.getStatusCode());
      outputMessage.getHeaders().putAll(responseEntity.getHeaders());
      returnValue = responseEntity.getBody();
      if (returnValue == null) {
        mavContainer.setRequestHandled(true);
        return;
      }
    }

    ServletRequest request = webRequest.getNativeRequest(ServletRequest.class);
    ShallowEtagHeaderFilter.disableContentCaching(request);

    Assert.isInstanceOf(ResponseBodyEmitter.class, returnValue);
    ResponseBodyEmitter emitter = (ResponseBodyEmitter) returnValue;
    emitter.extendResponse(outputMessage);

    // Commit the response and wrap to ignore further header changes
    outputMessage.getBody();
    outputMessage = new StreamingServletServerHttpResponse(outputMessage);

    DeferredResult<?> deferredResult = new DeferredResult<Object>(emitter.getTimeout());
    WebAsyncUtils.getAsyncManager(webRequest)
        .startDeferredResultProcessing(deferredResult, mavContainer);

    HttpMessageConvertingHandler handler =
        new HttpMessageConvertingHandler(outputMessage, deferredResult);
    emitter.initialize(handler);
  }
Esempio n. 10
0
  @Override
  protected void extendResponse(ServerHttpResponse outputMessage) {
    super.extendResponse(outputMessage);

    HttpHeaders headers = outputMessage.getHeaders();
    if (headers.getContentType() == null) {
      headers.setContentType(new MediaType("text", "event-stream"));
    }
  }
  @Override
  public void handleRequestInternal(
      ServerHttpRequest request,
      ServerHttpResponse response,
      AbstractHttpSockJsSession sockJsSession)
      throws SockJsException {

    try {
      String callback = request.getQueryParams().getFirst("c");
      if (!StringUtils.hasText(callback)) {
        response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        response.getBody().write("\"callback\" parameter required".getBytes("UTF-8"));
        return;
      }
    } catch (Throwable t) {
      sockJsSession.tryCloseWithSockJsTransportError(t, CloseStatus.SERVER_ERROR);
      throw new SockJsTransportFailureException("Failed to send error", sockJsSession.getId(), t);
    }

    super.handleRequestInternal(request, response, sockJsSession);
  }
  protected void handleRequestInternal(
      ServerHttpRequest request,
      ServerHttpResponse response,
      AbstractHttpSockJsSession sockJsSession)
      throws SockJsException {

    if (sockJsSession.isNew()) {
      if (logger.isDebugEnabled()) {
        logger.debug(request.getMethod() + " " + request.getURI());
      }
      sockJsSession.handleInitialRequest(request, response, getFrameFormat(request));
    } else if (sockJsSession.isClosed()) {
      if (logger.isDebugEnabled()) {
        logger.debug("Connection already closed (but not removed yet) for " + sockJsSession);
      }
      SockJsFrame frame = SockJsFrame.closeFrameGoAway();
      try {
        response.getBody().write(frame.getContentBytes());
      } catch (IOException ex) {
        throw new SockJsException("Failed to send " + frame, sockJsSession.getId(), ex);
      }
    } else if (!sockJsSession.isActive()) {
      if (logger.isTraceEnabled()) {
        logger.trace("Starting " + getTransportType() + " async request.");
      }
      sockJsSession.handleSuccessiveRequest(request, response, getFrameFormat(request));
    } else {
      if (logger.isDebugEnabled()) {
        logger.debug(
            "Another " + getTransportType() + " connection still open for " + sockJsSession);
      }
      String formattedFrame =
          getFrameFormat(request).format(SockJsFrame.closeFrameAnotherConnectionOpen());
      try {
        response.getBody().write(formattedFrame.getBytes(SockJsFrame.CHARSET));
      } catch (IOException ex) {
        throw new SockJsException("Failed to send " + formattedFrame, sockJsSession.getId(), ex);
      }
    }
  }
  @Override
  public final void handleRequest(
      ServerHttpRequest request,
      ServerHttpResponse response,
      WebSocketHandler wsHandler,
      SockJsSession wsSession)
      throws SockJsException {

    AbstractHttpSockJsSession sockJsSession = (AbstractHttpSockJsSession) wsSession;

    String protocol = null; // https://github.com/sockjs/sockjs-client/issues/130
    sockJsSession.setAcceptedProtocol(protocol);

    // Set content type before writing
    response.getHeaders().setContentType(getContentType());

    handleRequestInternal(request, response, sockJsSession);
  }
  @Override
  protected void beforeBodyWriteInternal(
      MappingJacksonValue bodyContainer,
      MediaType contentType,
      MethodParameter returnType,
      ServerHttpRequest request,
      ServerHttpResponse response) {

    HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();

    for (String name : this.jsonpQueryParamNames) {
      String value = servletRequest.getParameter(name);
      if (value != null) {
        MediaType contentTypeToUse = getContentType(contentType, request, response);
        response.getHeaders().setContentType(contentTypeToUse);
        bodyContainer.setJsonpFunction(value);
        return;
      }
    }
  }
  /**
   * Handle all requests, except the first one, to receive messages on a SockJS HTTP transport based
   * session.
   *
   * <p>Long polling-based transports (e.g. "xhr", "jsonp") complete the request after writing any
   * buffered message frames (or the next one). Streaming-based transports ("xhr_streaming",
   * "eventsource", and "htmlfile") leave the response open longer for further streaming of message
   * frames but will also close it eventually after some amount of data has been sent.
   *
   * @param request the current request
   * @param response the current response
   * @param frameFormat the transport-specific SocksJS frame format to use
   */
  public void handleSuccessiveRequest(
      ServerHttpRequest request, ServerHttpResponse response, SockJsFrameFormat frameFormat)
      throws SockJsException {

    synchronized (this.responseLock) {
      try {
        if (isClosed()) {
          response.getBody().write(SockJsFrame.closeFrameGoAway().getContentBytes());
        }
        this.response = response;
        this.frameFormat = frameFormat;
        this.asyncRequestControl = request.getAsyncRequestControl(response);
        writePrelude(request, response);
        startAsyncRequest();
      } catch (Throwable ex) {
        tryCloseWithSockJsTransportError(ex, CloseStatus.SERVER_ERROR);
        throw new SockJsTransportFailureException(
            "Failed to handle SockJS receive request", getId(), ex);
      }
    }
  }
 public StreamingServletServerHttpResponse(ServerHttpResponse delegate) {
   this.delegate = delegate;
   this.mutableHeaders.putAll(delegate.getHeaders());
 }
 @Override
 public void handle(ServerHttpRequest request, ServerHttpResponse response) throws IOException {
   response.setStatusCode(this.status);
 }
 protected void handleInvalidUpgradeHeader(ServerHttpRequest request, ServerHttpResponse response)
     throws IOException {
   logger.debug("Invalid Upgrade header " + request.getHeaders().getUpgrade());
   response.setStatusCode(HttpStatus.BAD_REQUEST);
   response.getBody().write("Can \"Upgrade\" only to \"WebSocket\".".getBytes("UTF-8"));
 }
 protected void handleInvalidConnectHeader(ServerHttpRequest request, ServerHttpResponse response)
     throws IOException {
   logger.debug("Invalid Connection header " + request.getHeaders().getConnection());
   response.setStatusCode(HttpStatus.BAD_REQUEST);
   response.getBody().write("\"Connection\" must be \"upgrade\".".getBytes("UTF-8"));
 }
 protected void addCacheHeaders(ServerHttpResponse response) {
   response.getHeaders().setCacheControl("public, max-age=" + ONE_YEAR);
   response.getHeaders().setExpires(new Date().getTime() + ONE_YEAR * 1000);
 }
 protected void sendMethodNotAllowed(ServerHttpResponse response, List<HttpMethod> httpMethods)
     throws IOException {
   logger.debug("Sending Method Not Allowed (405)");
   response.setStatusCode(HttpStatus.METHOD_NOT_ALLOWED);
   response.getHeaders().setAllow(new HashSet<HttpMethod>(httpMethods));
 }
 protected void addNoCacheHeaders(ServerHttpResponse response) {
   response.getHeaders().setCacheControl("no-store, no-cache, must-revalidate, max-age=0");
 }
  @Override
  protected void handleTransportRequest(
      ServerHttpRequest request,
      ServerHttpResponse response,
      WebSocketHandler handler,
      String sessionId,
      String transport)
      throws SockJsException {

    TransportType transportType = TransportType.fromValue(transport);
    if (transportType == null) {
      logger.error("Unknown transport type for " + request.getURI());
      response.setStatusCode(HttpStatus.NOT_FOUND);
      return;
    }

    TransportHandler transportHandler = this.handlers.get(transportType);
    if (transportHandler == null) {
      logger.error("No TransportHandler for " + request.getURI());
      response.setStatusCode(HttpStatus.NOT_FOUND);
      return;
    }

    HttpMethod supportedMethod = transportType.getHttpMethod();
    if (!supportedMethod.equals(request.getMethod())) {
      if (HttpMethod.OPTIONS.equals(request.getMethod()) && transportType.supportsCors()) {
        if (checkAndAddCorsHeaders(request, response, HttpMethod.OPTIONS, supportedMethod)) {
          response.setStatusCode(HttpStatus.NO_CONTENT);
          addCacheHeaders(response);
        }
      } else if (transportType.supportsCors()) {
        sendMethodNotAllowed(response, supportedMethod, HttpMethod.OPTIONS);
      } else {
        sendMethodNotAllowed(response, supportedMethod);
      }
      return;
    }

    HandshakeInterceptorChain chain = new HandshakeInterceptorChain(this.interceptors, handler);
    SockJsException failure = null;

    try {
      SockJsSession session = this.sessions.get(sessionId);
      if (session == null) {
        if (transportHandler instanceof SockJsSessionFactory) {
          Map<String, Object> attributes = new HashMap<String, Object>();
          if (!chain.applyBeforeHandshake(request, response, attributes)) {
            return;
          }
          SockJsSessionFactory sessionFactory = (SockJsSessionFactory) transportHandler;
          session = createSockJsSession(sessionId, sessionFactory, handler, attributes);
        } else {
          response.setStatusCode(HttpStatus.NOT_FOUND);
          if (logger.isDebugEnabled()) {
            logger.debug(
                "Session not found, sessionId="
                    + sessionId
                    + ". The session may have been closed "
                    + "(e.g. missed heart-beat) while a message was coming in.");
          }
          return;
        }
      }

      if (transportType.sendsNoCacheInstruction()) {
        addNoCacheHeaders(response);
      }

      if (transportType.supportsCors()) {
        if (!checkAndAddCorsHeaders(request, response)) {
          return;
        }
      }

      transportHandler.handleRequest(request, response, handler, session);
      chain.applyAfterHandshake(request, response, null);
    } catch (SockJsException ex) {
      failure = ex;
    } catch (Throwable ex) {
      failure =
          new SockJsException("Uncaught failure for request " + request.getURI(), sessionId, ex);
    } finally {
      if (failure != null) {
        chain.applyAfterHandshake(request, response, failure);
        throw failure;
      }
    }
  }
  /**
   * TODO
   *
   * @param request
   * @param response
   * @param sockJsPath
   * @throws Exception
   */
  @Override
  public final void handleRequest(
      ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler handler)
      throws IOException, TransportErrorException {

    String sockJsPath = getSockJsPath(request);
    if (sockJsPath == null) {
      logger.warn(
          "Could not determine SockJS path for URL \""
              + request.getURI().getPath()
              + ". Consider setting validSockJsPrefixes.");
      response.setStatusCode(HttpStatus.NOT_FOUND);
      return;
    }

    logger.debug(request.getMethod() + " with SockJS path [" + sockJsPath + "]");

    try {
      request.getHeaders();
    } catch (IllegalArgumentException ex) {
      // Ignore invalid Content-Type (TODO)
    }

    try {
      if (sockJsPath.equals("") || sockJsPath.equals("/")) {
        response
            .getHeaders()
            .setContentType(new MediaType("text", "plain", Charset.forName("UTF-8")));
        response.getBody().write("Welcome to SockJS!\n".getBytes("UTF-8"));
        return;
      } else if (sockJsPath.equals("/info")) {
        this.infoHandler.handle(request, response);
        return;
      } else if (sockJsPath.matches("/iframe[0-9-.a-z_]*.html")) {
        this.iframeHandler.handle(request, response);
        return;
      } else if (sockJsPath.equals("/websocket")) {
        handleRawWebSocketRequest(request, response, handler);
        return;
      }

      String[] pathSegments = StringUtils.tokenizeToStringArray(sockJsPath.substring(1), "/");
      if (pathSegments.length != 3) {
        logger.warn("Expected \"/{server}/{session}/{transport}\" but got \"" + sockJsPath + "\"");
        response.setStatusCode(HttpStatus.NOT_FOUND);
        return;
      }

      String serverId = pathSegments[0];
      String sessionId = pathSegments[1];
      String transport = pathSegments[2];

      if (!validateRequest(serverId, sessionId, transport)) {
        response.setStatusCode(HttpStatus.NOT_FOUND);
        return;
      }

      handleTransportRequest(
          request, response, sessionId, TransportType.fromValue(transport), handler);
    } finally {
      response.flush();
    }
  }