Package com.google.caja.service

Source Code of com.google.caja.service.CajolingServlet

// Copyright (C) 2010 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.caja.service;

import com.google.caja.lexer.FetchedData;
import com.google.caja.lexer.InputSource;
import com.google.caja.lexer.escaping.Escaping;
import com.google.caja.reporting.Message;
import com.google.caja.reporting.MessageContext;
import com.google.caja.reporting.MessageQueue;
import com.google.caja.reporting.SimpleMessageQueue;
import com.google.caja.util.Pair;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
* Handles HTTP servlet invocation of a {@link CajolingService}.
*
* @author jasvir@gmail.com (Jasvir Nagra)
* @author ihab.awad@gmail.com (Ihab Awad)
*/
public class CajolingServlet extends HttpServlet {
  private static final long serialVersionUID = 5055670217887121398L;
  private static final Pair<String, String> UMP =
    Pair.pair("Access-Control-Allow-Origin", "*");

  private static class HttpContentHandlerArgs extends ContentHandlerArgs {
    private final HttpServletRequest request;

    public HttpContentHandlerArgs(HttpServletRequest request) {
      this.request = request;
    }

    @Override
    public String get(String name) {
      return request.getParameter(name);
    }
  }

  private final CajolingService service;

  /**
   * Appengine insists on a zero-argument constructor
   *
   * @deprecated Do not use this; instead pass in a CajolingService you've
   *             constructed with the correct host argument (self URL).
   */
  @Deprecated
  public CajolingServlet() {
    this(new CajolingService());
  }

  public CajolingServlet(CajolingService service) {
    this.service = service;
  }

  /**
   * Set an error status on a servlet response and close its stream cleanly.
   *
   * @param resp a servlet response.
   * @param error an error message.
   */
  private static void closeBadRequest(HttpServletResponse resp,
      int httpStatus, String error)
      throws ServletException {
    try {
      resp.sendError(httpStatus, error);
    } catch (IOException ex) {
      throw (ServletException) new ServletException().initCause(ex);
    }
  }

  /**
   * Set an error status on a servlet response and close its stream cleanly.
   *
   * @param resp a servlet response.
   * @param httpStatus status response level.
   * @param mq a {@link MessageQueue} with messages to include as an error page.
   */
  private static void closeBadRequest(HttpServletResponse resp,
      int httpStatus, MessageQueue mq)
      throws ServletException {
    closeBadRequest(resp, httpStatus, serializeMessageQueue(mq));
  }

  // TODO(jasvir): The service like the gwt version should accumulate
  // input sources and use html snippet producer to produce messages
  private static String serializeMessageQueue(MessageQueue mq) {
    StringBuilder sb = new StringBuilder();
    MessageContext mc = new MessageContext();
    for (Message m : mq.getMessages()) {
      sb.append(m.getMessageLevel().name()).append(": ");
      Escaping.escapeXml(m.format(mc), false, sb);
      sb.append("\n");
    }
    return sb.toString();
  }

  @Override
  protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException, IOException {
    // CORS requires that browsers do an OPTIONS request before allowing
    // cross-site POSTs.  UMP does not require this, but no browser implements
    // UMP at this time.  So, we reply to the OPTIONS request to trick
    // browsers into effectively implementing UMP.
    resp.setHeader("Access-Control-Allow-Origin", "*");
    resp.setHeader("Access-Control-Allow-Methods", "GET, POST");
    resp.setHeader("Access-Control-Allow-Headers", "Content-Type");
    resp.setHeader("Access-Control-Max-Age", "86400");
  }

  @Override
  public void doPost(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException {
    if (req.getContentType() == null) {
      closeBadRequest(resp, HttpServletResponse.SC_BAD_REQUEST,
          "Supplied Content-type is null");
      return;
    }

    FetchedData fetchedData;
    try {
      fetchedData = FetchedData.fromStream(
          req.getInputStream(), req.getContentType(),
          req.getCharacterEncoding(),
          InputSource.UNKNOWN);
    } catch (IOException e) {
      closeBadRequest(resp, HttpServletResponse.SC_BAD_REQUEST,
          "Error decoding POST data");
      return;
    }

    handle(req, resp, new HttpContentHandlerArgs(req), fetchedData);
  }

  @Override
  public void doGet(HttpServletRequest req, HttpServletResponse resp)
      throws ServletException {
    handle(req, resp, new HttpContentHandlerArgs(req), null);
  }

  private void handle(HttpServletRequest req, HttpServletResponse resp,
                      ContentHandlerArgs args,
                      FetchedData inputFetchedData)
      throws ServletException {
    // URL path parameters can trick IE into misinterpreting responses as HTML
    if (req.getRequestURI().contains(";")) {
      throw new ServletException("Invalid URL path parameter");
    }

    MessageQueue mq = new SimpleMessageQueue();
    FetchedData result = service.handle(inputFetchedData, args, mq);
    if (result == null) {
      closeBadRequest(resp, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, mq);
      return;
    }

    resp.setStatus(HttpServletResponse.SC_OK);

    String responseContentType = result.getContentType();
    if (result.getCharSet() != null) {
      responseContentType += ";charset=" + result.getCharSet();
    }
    if (containsNewline(responseContentType)) {
      throw new IllegalArgumentException(responseContentType);
    }

    try {
      byte[] content = result.getByteContent();
      resp.setContentType(responseContentType);
      resp.setContentLength(content.length);
      resp.setHeader(UMP.a, UMP.b);
      resp.setHeader("X-Content-Type-Options", "nosniff");

      resp.getOutputStream().write(content);
      resp.getOutputStream().close();
    } catch (IOException ex) {
      throw (ServletException) new ServletException().initCause(ex);
    }
  }

  // Used to protect against header splitting attacks.
  private static boolean containsNewline(String s) {
    return s.indexOf('\n') >= 0 || s.indexOf('\r') >= 0;
  }
}
TOP

Related Classes of com.google.caja.service.CajolingServlet

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.
yTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-20639858-1', 'auto'); ga('send', 'pageview');