Example usage for javax.servlet.http HttpServletResponse SC_SEE_OTHER

List of usage examples for javax.servlet.http HttpServletResponse SC_SEE_OTHER

Introduction

In this page you can find the example usage for javax.servlet.http HttpServletResponse SC_SEE_OTHER.

Prototype

int SC_SEE_OTHER

To view the source code for javax.servlet.http HttpServletResponse SC_SEE_OTHER.

Click Source Link

Document

Status code (303) indicating that the response to the request can be found under a different URI.

Usage

From source file:com.boylesoftware.web.Router.java

/**
 * Send request for user authentication, which can be a redirect to the
 * login page, or the 401 HTTP code./*from  ww  w .ja va 2  s.c  om*/
 *
 * @param webapp The web-application.
 * @param request The HTTP request.
 * @param response The HTTP response.
 *
 * @throws ServletException If an error happens.
 */
private void sendRequestForAuthentication(final AbstractWebApplication webapp, final HttpServletRequest request,
        final HttpServletResponse response) throws ServletException {

    LooseCannon.heel();

    final String loginPageURI = webapp.getRouterConfiguration().getLoginPageURI();
    if (loginPageURI != null) {

        try (final PooledStringBuffer buf = StringBufferPool.get()) {
            final StringBuilder sb = buf.getStringBuilder();

            sb.append(request.getRequestURI());
            final String queryString = request.getQueryString();
            if (queryString != null)
                sb.append('?').append(queryString);
            final String targetURI = sb.toString();
            sb.setLength(0);

            sb.append("https://").append(request.getServerName());

            final int httpsPort = webapp.getHTTPSPort();
            if (httpsPort != 443)
                sb.append(':').append(httpsPort);

            sb.append(StringUtils.emptyIfNull(request.getContextPath())).append(loginPageURI).append('?')
                    .append(Authenticator.TARGET_URI).append('=');

            try {
                sb.append(URLEncoder.encode(targetURI, "UTF-8"));
            } catch (final UnsupportedEncodingException e) {
                throw new ServletException("UTF-8 is unsupported.", e);
            }

            response.setStatus(HttpServletResponse.SC_SEE_OTHER);
            response.setHeader("Location", sb.toString());
        }

    } else {
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        // TODO: configure realm in the application configuration
        response.setHeader("WWW-Authenticate", "Basic realm=\"Application\"");
    }
}

From source file:de.mpg.mpdl.inge.pubman.web.sword.SwordUtil.java

/**
 * Logs in the given user with the given password.
 * /*from w w w.  j  a  v a 2  s  . c  o  m*/
 * @param userid The id of the user to log in.
 * @param password The password of the user to log in.
 * @return The handle for the logged in user.
 * @throws HttpException
 * @throws IOException
 * @throws ServiceException
 * @throws URISyntaxException
 */
@Deprecated
public String loginUser(String userid, String password)
        throws HttpException, IOException, ServiceException, URISyntaxException {
    String frameworkUrl = PropertyReader.getFrameworkUrl();
    StringTokenizer tokens = new StringTokenizer(frameworkUrl, "//");
    if (tokens.countTokens() != NUMBER_OF_URL_TOKENS) {
        throw new IOException(
                "Url in the config file is in the wrong format, needs to be http://<host>:<port>");
    }
    tokens.nextToken();
    StringTokenizer hostPort = new StringTokenizer(tokens.nextToken(), ":");

    if (hostPort.countTokens() != NUMBER_OF_URL_TOKENS) {
        throw new IOException(
                "Url in the config file is in the wrong format, needs to be http://<host>:<port>");
    }
    String host = hostPort.nextToken();
    int port = Integer.parseInt(hostPort.nextToken());

    HttpClient client = new HttpClient();

    client.getHostConfiguration().setHost(host, port, "http");
    client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);

    PostMethod login = new PostMethod(frameworkUrl + "/aa/j_spring_security_check");
    login.addParameter("j_username", userid);
    login.addParameter("j_password", password);

    client.executeMethod(login);

    login.releaseConnection();
    CookieSpec cookiespec = CookiePolicy.getDefaultSpec();
    Cookie[] logoncookies = cookiespec.match(host, port, "/", false, client.getState().getCookies());

    Cookie sessionCookie = logoncookies[0];

    PostMethod postMethod = new PostMethod(LOGIN_URL);
    postMethod.addParameter("target", frameworkUrl);
    client.getState().addCookie(sessionCookie);
    client.executeMethod(postMethod);

    if (HttpServletResponse.SC_SEE_OTHER != postMethod.getStatusCode()) {
        throw new HttpException("Wrong status code: " + login.getStatusCode());
    }

    String userHandle = null;
    Header[] headers = postMethod.getResponseHeaders();
    for (int i = 0; i < headers.length; ++i) {
        if ("Location".equals(headers[i].getName())) {
            String location = headers[i].getValue();
            int index = location.indexOf('=');
            userHandle = new String(Base64.decode(location.substring(index + 1, location.length())));
        }
    }
    if (userHandle == null) {
        throw new ServiceException("User not logged in.");
    }
    return userHandle;
}

From source file:de.mpg.escidoc.pubman.sword.SwordUtil.java

/**
 * Logs in the given user with the given password.
 * @param userid The id of the user to log in.
 * @param password The password of the user to log in.
 * @return The handle for the logged in user.
 * @throws HttpException/*from w  w w  .  jav  a 2  s  .com*/
 * @throws IOException
 * @throws ServiceException
 * @throws URISyntaxException
 */
@Deprecated
public String loginUser(String userid, String password)
        throws HttpException, IOException, ServiceException, URISyntaxException {
    String frameworkUrl = ServiceLocator.getFrameworkUrl();
    StringTokenizer tokens = new StringTokenizer(frameworkUrl, "//");
    if (tokens.countTokens() != NUMBER_OF_URL_TOKENS) {
        throw new IOException(
                "Url in the config file is in the wrong format, needs to be http://<host>:<port>");
    }
    tokens.nextToken();
    StringTokenizer hostPort = new StringTokenizer(tokens.nextToken(), ":");

    if (hostPort.countTokens() != NUMBER_OF_URL_TOKENS) {
        throw new IOException(
                "Url in the config file is in the wrong format, needs to be http://<host>:<port>");
    }
    String host = hostPort.nextToken();
    int port = Integer.parseInt(hostPort.nextToken());

    HttpClient client = new HttpClient();

    client.getHostConfiguration().setHost(host, port, "http");
    client.getParams().setCookiePolicy(CookiePolicy.BROWSER_COMPATIBILITY);

    PostMethod login = new PostMethod(frameworkUrl + "/aa/j_spring_security_check");
    login.addParameter("j_username", userid);
    login.addParameter("j_password", password);

    client.executeMethod(login);

    login.releaseConnection();
    CookieSpec cookiespec = CookiePolicy.getDefaultSpec();
    Cookie[] logoncookies = cookiespec.match(host, port, "/", false, client.getState().getCookies());

    Cookie sessionCookie = logoncookies[0];

    PostMethod postMethod = new PostMethod(LOGIN_URL);
    postMethod.addParameter("target", frameworkUrl);
    client.getState().addCookie(sessionCookie);
    client.executeMethod(postMethod);

    if (HttpServletResponse.SC_SEE_OTHER != postMethod.getStatusCode()) {
        throw new HttpException("Wrong status code: " + login.getStatusCode());
    }

    String userHandle = null;
    Header[] headers = postMethod.getResponseHeaders();
    for (int i = 0; i < headers.length; ++i) {
        if ("Location".equals(headers[i].getName())) {
            String location = headers[i].getValue();
            int index = location.indexOf('=');
            userHandle = new String(Base64.decode(location.substring(index + 1, location.length())));
        }
    }
    if (userHandle == null) {
        throw new ServiceException("User not logged in.");
    }
    return userHandle;
}

From source file:edu.cornell.mannlib.vitro.webapp.edit.n3editing.controller.EditRequestDispatchController.java

private ResponseValues processSkipEditForm(VitroRequest vreq) {
    ParamMap params = new ParamMap();
    params.put("uri", EditConfigurationUtils.getObjectUri(vreq));
    params.put("relatedSubjectUri", EditConfigurationUtils.getSubjectUri(vreq));
    params.put("relatingPredicateUri", EditConfigurationUtils.getPredicateUri(vreq));

    return new DirectRedirectResponseValues(UrlBuilder.getUrl(UrlBuilder.Route.INDIVIDUAL, params),
            HttpServletResponse.SC_SEE_OTHER);
}

From source file:helma.servlet.AbstractServletClient.java

void sendRedirect(HttpServletRequest req, HttpServletResponse res, String url, int status) {
    String location = url;/*from w  w w  . jav a 2  s  .  c o m*/

    if (url.indexOf("://") == -1) {
        // need to transform a relative URL into an absolute one
        String scheme = req.getScheme();
        StringBuffer loc = new StringBuffer(scheme);

        loc.append("://");
        loc.append(req.getServerName());

        int p = req.getServerPort();

        // check if we need to include server port
        if ((p > 0) && (("http".equals(scheme) && (p != 80)) || ("https".equals(scheme) && (p != 443)))) {
            loc.append(":");
            loc.append(p);
        }

        if (!url.startsWith("/")) {
            String requri = req.getRequestURI();
            int lastSlash = requri.lastIndexOf("/");

            if (lastSlash == (requri.length() - 1)) {
                loc.append(requri);
            } else if (lastSlash > -1) {
                loc.append(requri.substring(0, lastSlash + 1));
            } else {
                loc.append("/");
            }
        }

        loc.append(url);
        location = loc.toString();
    }

    // if status code was explicitly set use that, or use 303 for HTTP 1.1,
    // 302 for earlier protocol versions
    if (status >= 301 && status <= 303) {
        res.setStatus(status);
    } else if (isOneDotOne(req.getProtocol())) {
        res.setStatus(HttpServletResponse.SC_SEE_OTHER);
    } else {
        res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
    }

    res.setContentType("text/html");
    res.setHeader("Location", location);
}

From source file:axiom.servlet.AbstractServletClient.java

void sendRedirect(HttpServletRequest req, HttpServletResponse res, String url) {
    String location = url;//from w w  w.  jav  a2  s  .com

    if (url.indexOf("://") == -1) {
        // need to transform a relative URL into an absolute one
        String scheme = req.getScheme();
        StringBuffer loc = new StringBuffer(scheme);

        loc.append("://");
        String hostname = req.getServerName();
        boolean forwarded = false;
        if (req.getHeader("X-Forwarded-Host") != null) {
            hostname = req.getHeader("X-Forwarded-Host");
            forwarded = true;
        }
        loc.append(hostname);

        int p = (!forwarded) ? req.getServerPort() : 80;

        // check if we need to include server port
        if ((p > 0) && (("http".equals(scheme) && (p != 80)) || ("https".equals(scheme) && (p != 443)))) {
            loc.append(":");
            loc.append(p);
        }

        if (!url.startsWith("/")) {
            String requri = req.getRequestURI();
            int lastSlash = requri.lastIndexOf("/");

            if (lastSlash == (requri.length() - 1)) {
                loc.append(requri);
            } else if (lastSlash > -1) {
                loc.append(requri.substring(0, lastSlash + 1));
            } else {
                loc.append("/");
            }
        }

        loc.append(url);
        location = loc.toString();
    }

    // send status code 303 for HTTP 1.1, 302 otherwise
    if (isOneDotOne(req.getProtocol())) {
        res.setStatus(HttpServletResponse.SC_SEE_OTHER);
    } else {
        res.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
    }

    res.setContentType("text/html");
    res.setHeader("Location", location);
}

From source file:hello.MyPostHTTP.java

@Override
public void onTrigger(final ProcessContext context, final ProcessSession session) {

    final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
    requestConfigBuilder.setConnectionRequestTimeout(
            context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    requestConfigBuilder.setConnectTimeout(
            context.getProperty(CONNECTION_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    requestConfigBuilder.setRedirectsEnabled(false);
    requestConfigBuilder/*from w ww .j a v  a2s  .c o  m*/
            .setSocketTimeout(context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    final RequestConfig requestConfig = requestConfigBuilder.build();

    final StreamThrottler throttler = throttlerRef.get();
    final ProcessorLog logger = getLogger();

    String lastUrl = null;
    long bytesToSend = 0L;

    final List<FlowFile> toSend = new ArrayList<>();
    CloseableHttpClient client = null;
    final String transactionId = UUID.randomUUID().toString();

    final ObjectHolder<String> dnHolder = new ObjectHolder<>("none");
    while (true) {
        FlowFile flowFile = session.get();
        if (flowFile == null) {
            break;
        }

        final String url = context.getProperty(URL).evaluateAttributeExpressions(flowFile).getValue();
        try {
            new java.net.URL(url);
        } catch (final MalformedURLException e) {
            logger.error(
                    "After substituting attribute values for {}, URL is {}; this is not a valid URL, so routing to failure",
                    new Object[] { flowFile, url });
            flowFile = session.penalize(flowFile);
            session.transfer(flowFile, REL_FAILURE);
            continue;
        }

        // If this FlowFile doesn't have the same url, throw it back on the queue and stop grabbing FlowFiles
        if (lastUrl != null && !lastUrl.equals(url)) {
            session.transfer(flowFile);
            break;
        }

        lastUrl = url;
        toSend.add(flowFile);

        if (client == null) {
            final Config config = getConfig(url, context);
            final HttpClientConnectionManager conMan = config.getConnectionManager();

            final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
            clientBuilder.setConnectionManager(conMan);
            clientBuilder.addInterceptorFirst(new HttpResponseInterceptor() {
                @Override
                public void process(final HttpResponse response, final HttpContext httpContext)
                        throws HttpException, IOException {
                    final HttpCoreContext coreContext = HttpCoreContext.adapt(httpContext);
                    final ManagedHttpClientConnection conn = coreContext
                            .getConnection(ManagedHttpClientConnection.class);
                    if (!conn.isOpen()) {
                        return;
                    }

                    final SSLSession sslSession = conn.getSSLSession();

                    if (sslSession != null) {
                        final X509Certificate[] certChain = sslSession.getPeerCertificateChain();
                        if (certChain == null || certChain.length == 0) {
                            throw new SSLPeerUnverifiedException("No certificates found");
                        }

                        final X509Certificate cert = certChain[0];
                        dnHolder.set(cert.getSubjectDN().getName().trim());
                    }
                }
            });

            clientBuilder.disableAutomaticRetries();
            clientBuilder.disableContentCompression();

            client = clientBuilder.build();
        }

        bytesToSend += flowFile.getSize();
        break;
    }

    if (toSend.isEmpty()) {
        return;
    }

    final String url = lastUrl;
    final HttpPost post = new HttpPost(url);
    final List<FlowFile> flowFileList = toSend;

    String userName = "Chris";
    String password = "password";
    final MultipartEntityBuilder builder = MultipartEntityBuilder.create();
    builder.addTextBody("userName", userName);
    builder.addTextBody("password", password);
    for (final FlowFile flowFile : flowFileList) {
        session.read(flowFile, new InputStreamCallback() {
            @Override
            public void process(final InputStream rawIn) throws IOException {
                InputStream in = new ByteArrayInputStream(IOUtils.toByteArray(rawIn));
                builder.addBinaryBody("file", in, ContentType.DEFAULT_BINARY, "filename");
            }
        });
    }

    final HttpEntity entity2 = builder.build();

    post.setEntity(entity2);
    post.setConfig(requestConfig);

    final String contentType;

    contentType = DEFAULT_CONTENT_TYPE;
    post.setHeader(CONTENT_TYPE_HEADER, contentType);
    post.setHeader(FLOWFILE_CONFIRMATION_HEADER, "true");
    post.setHeader(PROTOCOL_VERSION_HEADER, PROTOCOL_VERSION);
    post.setHeader(TRANSACTION_ID_HEADER, transactionId);

    // Do the actual POST
    final String flowFileDescription = toSend.size() <= 10 ? toSend.toString() : toSend.size() + " FlowFiles";

    final String uploadDataRate;
    final long uploadMillis;
    CloseableHttpResponse response = null;
    try {
        final StopWatch stopWatch = new StopWatch(true);
        response = client.execute(post);
        // consume input stream entirely, ignoring its contents. If we
        // don't do this, the Connection will not be returned to the pool
        EntityUtils.consume(response.getEntity());
        stopWatch.stop();
        uploadDataRate = stopWatch.calculateDataRate(bytesToSend);
        uploadMillis = stopWatch.getDuration(TimeUnit.MILLISECONDS);
    } catch (final IOException e) {
        logger.error("Failed to Post {} due to {}; transferring to failure",
                new Object[] { flowFileDescription, e });
        context.yield();
        for (FlowFile flowFile : toSend) {
            flowFile = session.penalize(flowFile);
            session.transfer(flowFile, REL_FAILURE);
        }
        return;
    } finally {
        if (response != null) {
            try {
                response.close();
            } catch (final IOException e) {
                getLogger().warn("Failed to close HTTP Response due to {}", new Object[] { e });
            }
        }
    }

    // If we get a 'SEE OTHER' status code and an HTTP header that indicates that the intent
    // of the Location URI is a flowfile hold, we will store this holdUri. This prevents us
    // from posting to some other webservice and then attempting to delete some resource to which
    // we are redirected
    final int responseCode = response.getStatusLine().getStatusCode();
    final String responseReason = response.getStatusLine().getReasonPhrase();
    String holdUri = null;
    if (responseCode == HttpServletResponse.SC_SEE_OTHER) {
        final Header locationUriHeader = response.getFirstHeader(LOCATION_URI_INTENT_NAME);
        if (locationUriHeader != null) {
            if (LOCATION_URI_INTENT_VALUE.equals(locationUriHeader.getValue())) {
                final Header holdUriHeader = response.getFirstHeader(LOCATION_HEADER_NAME);
                if (holdUriHeader != null) {
                    holdUri = holdUriHeader.getValue();
                }
            }
        }

        if (holdUri == null) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error(
                        "Failed to Post {} to {}: sent content and received status code {}:{} but no Hold URI",
                        new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }
    }

    if (holdUri == null) {
        if (responseCode == HttpServletResponse.SC_SERVICE_UNAVAILABLE) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error(
                        "Failed to Post {} to {}: response code was {}:{}; will yield processing, "
                                + "since the destination is temporarily unavailable",
                        new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            context.yield();
            return;
        }

        if (responseCode >= 300) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error("Failed to Post {} to {}: response code was {}:{}",
                        new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }

        logger.info("Successfully Posted {} to {} in {} at a rate of {}", new Object[] { flowFileDescription,
                url, FormatUtils.formatMinutesSeconds(uploadMillis, TimeUnit.MILLISECONDS), uploadDataRate });

        for (final FlowFile flowFile : toSend) {
            session.getProvenanceReporter().send(flowFile, url, "Remote DN=" + dnHolder.get(), uploadMillis,
                    true);
            session.transfer(flowFile, REL_SUCCESS);
        }
        return;
    }

    //
    // the response indicated a Hold URI; delete the Hold.
    //
    // determine the full URI of the Flow File's Hold; Unfortunately, the responses that are returned have
    // changed over the past, so we have to take into account a few different possibilities.
    String fullHoldUri = holdUri;
    if (holdUri.startsWith("/contentListener")) {
        // If the Hold URI that we get starts with /contentListener, it may not really be /contentListener,
        // as this really indicates that it should be whatever we posted to -- if posting directly to the
        // ListenHTTP component, it will be /contentListener, but if posting to a proxy/load balancer, we may
        // be posting to some other URL.
        fullHoldUri = url + holdUri.substring(16);
    } else if (holdUri.startsWith("/")) {
        // URL indicates the full path but not hostname or port; use the same hostname & port that we posted
        // to but use the full path indicated by the response.
        int firstSlash = url.indexOf("/", 8);
        if (firstSlash < 0) {
            firstSlash = url.length();
        }
        final String beforeSlash = url.substring(0, firstSlash);
        fullHoldUri = beforeSlash + holdUri;
    } else if (!holdUri.startsWith("http")) {
        // Absolute URL
        fullHoldUri = url + (url.endsWith("/") ? "" : "/") + holdUri;
    }

    final HttpDelete delete = new HttpDelete(fullHoldUri);
    delete.setHeader(TRANSACTION_ID_HEADER, transactionId);

    while (true) {
        try {
            final HttpResponse holdResponse = client.execute(delete);
            EntityUtils.consume(holdResponse.getEntity());
            final int holdStatusCode = holdResponse.getStatusLine().getStatusCode();
            final String holdReason = holdResponse.getStatusLine().getReasonPhrase();
            if (holdStatusCode >= 300) {
                logger.error(
                        "Failed to delete Hold that destination placed on {}: got response code {}:{}; routing to failure",
                        new Object[] { flowFileDescription, holdStatusCode, holdReason });

                for (FlowFile flowFile : toSend) {
                    flowFile = session.penalize(flowFile);
                    session.transfer(flowFile, REL_FAILURE);
                }
                return;
            }

            logger.info("Successfully Posted {} to {} in {} milliseconds at a rate of {}",
                    new Object[] { flowFileDescription, url, uploadMillis, uploadDataRate });

            for (final FlowFile flowFile : toSend) {
                session.getProvenanceReporter().send(flowFile, url);
                session.transfer(flowFile, REL_SUCCESS);
            }
            return;
        } catch (final IOException e) {
            logger.warn("Failed to delete Hold that destination placed on {} due to {}",
                    new Object[] { flowFileDescription, e });
        }

        if (!isScheduled()) {
            context.yield();
            logger.warn(
                    "Failed to delete Hold that destination placed on {}; Processor has been stopped so routing FlowFile(s) to failure",
                    new Object[] { flowFileDescription });
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }
    }
}

From source file:de.escidoc.core.aa.servlet.Login.java

/**
 * Initializes the redirect to the provided URL and writes the provided page content to the writer of the {@link
 * HttpServletResponse}. The http status code is set to SEE_OTHER.
 *
 * @param response    The {@link HttpServletResponse}.
 * @param page        The page to write.
 * @param redirectUrl The URL to that the user shall be redirected.
 * @throws IOException Thrown in case of a failed i/o operation.
 *///  w ww.j  a  v a2  s  .  c  om
private static void sendRedirectingResponse(final HttpServletResponse response, final String page,
        final String redirectUrl) throws IOException {

    final PrintWriter writer = response.getWriter();
    writer.print(page);
    // TODO: which response/status code? sendRedirect uses 302. 307 must
    // not be used since this results in forwarding the post of login data.
    // Maybe, 303 should be used to force the browser to redirect with GET,
    // as redirect with POST is prohibited?
    // Or should a form be returned and the user posts the handle back to
    // the application (similar to Shibboleth's Browser/Post profile)?
    response.setStatus(HttpServletResponse.SC_SEE_OTHER);
    response.setHeader("Location", redirectUrl);
    //        response.flushBuffer();
}

From source file:com.cognitivemedicine.nifi.http.PostHTTP2.java

@Override
public void onTrigger(final ProcessContext context, final ProcessSession session) {
    final boolean sendAsFlowFile = context.getProperty(SEND_AS_FLOWFILE).asBoolean();
    final int compressionLevel = context.getProperty(COMPRESSION_LEVEL).asInteger();
    final String userAgent = context.getProperty(USER_AGENT).getValue();

    final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom();
    requestConfigBuilder.setConnectionRequestTimeout(
            context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    requestConfigBuilder.setConnectTimeout(
            context.getProperty(CONNECTION_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    requestConfigBuilder.setRedirectsEnabled(false);
    requestConfigBuilder//from   w w  w  .  j  a  va  2  s. co m
            .setSocketTimeout(context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
    final RequestConfig requestConfig = requestConfigBuilder.build();

    final StreamThrottler throttler = throttlerRef.get();
    final ProcessorLog logger = getLogger();

    final Double maxBatchBytes = context.getProperty(MAX_BATCH_SIZE).asDataSize(DataUnit.B);
    String lastUrl = null;
    long bytesToSend = 0L;

    final List<FlowFile> toSend = new ArrayList<>();
    DestinationAccepts destinationAccepts = null;
    CloseableHttpClient client = null;
    final String transactionId = UUID.randomUUID().toString();

    final ObjectHolder<String> dnHolder = new ObjectHolder<>("none");
    while (true) {
        FlowFile flowFile = session.get();
        if (flowFile == null) {
            break;
        }

        final String url = context.getProperty(URL).evaluateAttributeExpressions(flowFile).getValue();
        try {
            new java.net.URL(url);
        } catch (final MalformedURLException e) {
            logger.error(
                    "After substituting attribute values for {}, URL is {}; this is not a valid URL, so routing to failure",
                    new Object[] { flowFile, url });
            flowFile = session.penalize(flowFile);
            session.transfer(flowFile, REL_FAILURE);
            continue;
        }

        // If this FlowFile doesn't have the same url, throw it back on the queue and stop grabbing FlowFiles
        if (lastUrl != null && !lastUrl.equals(url)) {
            session.transfer(flowFile);
            break;
        }

        lastUrl = url;
        toSend.add(flowFile);

        if (client == null || destinationAccepts == null) {
            final Config config = getConfig(url, context);
            final HttpClientConnectionManager conMan = config.getConnectionManager();

            final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
            clientBuilder.setConnectionManager(conMan);
            clientBuilder.setUserAgent(userAgent);
            clientBuilder.addInterceptorFirst(new HttpResponseInterceptor() {
                @Override
                public void process(final HttpResponse response, final HttpContext httpContext)
                        throws HttpException, IOException {
                    HttpCoreContext coreContext = HttpCoreContext.adapt(httpContext);
                    ManagedHttpClientConnection conn = coreContext
                            .getConnection(ManagedHttpClientConnection.class);
                    if (!conn.isOpen()) {
                        return;
                    }

                    SSLSession sslSession = conn.getSSLSession();

                    if (sslSession != null) {
                        final X509Certificate[] certChain = sslSession.getPeerCertificateChain();
                        if (certChain == null || certChain.length == 0) {
                            throw new SSLPeerUnverifiedException("No certificates found");
                        }

                        final X509Certificate cert = certChain[0];
                        dnHolder.set(cert.getSubjectDN().getName().trim());
                    }
                }
            });

            clientBuilder.disableAutomaticRetries();
            clientBuilder.disableContentCompression();

            final String username = context.getProperty(USERNAME).getValue();
            final String password = context.getProperty(PASSWORD).getValue();
            // set the credentials if appropriate
            if (username != null) {
                final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                if (password == null) {
                    credentialsProvider.setCredentials(AuthScope.ANY,
                            new UsernamePasswordCredentials(username));
                } else {
                    credentialsProvider.setCredentials(AuthScope.ANY,
                            new UsernamePasswordCredentials(username, password));
                }
                ;
                clientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            }
            client = clientBuilder.build();

            // determine whether or not destination accepts flowfile/gzip
            destinationAccepts = config.getDestinationAccepts();
            if (destinationAccepts == null) {
                try {
                    if (sendAsFlowFile) {
                        destinationAccepts = getDestinationAcceptance(client, url, getLogger(), transactionId);
                    } else {
                        destinationAccepts = new DestinationAccepts(false, false, false, false, null);
                    }

                    config.setDestinationAccepts(destinationAccepts);
                } catch (IOException e) {
                    flowFile = session.penalize(flowFile);
                    session.transfer(flowFile, REL_FAILURE);
                    logger.error(
                            "Unable to communicate with destination {} to determine whether or not it can accept flowfiles/gzip; routing {} to failure due to {}",
                            new Object[] { url, flowFile, e });
                    context.yield();
                    return;
                }
            }
        }

        // if we are not sending as flowfile, or if the destination doesn't accept V3 or V2 (streaming) format,
        // then only use a single FlowFile
        if (!sendAsFlowFile
                || (!destinationAccepts.isFlowFileV3Accepted() && !destinationAccepts.isFlowFileV2Accepted())) {
            break;
        }

        bytesToSend += flowFile.getSize();
        if (bytesToSend > maxBatchBytes.longValue()) {
            break;
        }
    }

    if (toSend.isEmpty()) {
        return;
    }

    final String url = lastUrl;
    final HttpPost post = new HttpPost(url);
    final List<FlowFile> flowFileList = toSend;
    final DestinationAccepts accepts = destinationAccepts;
    final boolean isDestinationLegacyNiFi = accepts.getProtocolVersion() == null;

    final EntityTemplate entity = new EntityTemplate(new ContentProducer() {
        @Override
        public void writeTo(final OutputStream rawOut) throws IOException {
            final OutputStream throttled = (throttler == null) ? rawOut
                    : throttler.newThrottledOutputStream(rawOut);
            OutputStream wrappedOut = new BufferedOutputStream(throttled);
            if (compressionLevel > 0 && accepts.isGzipAccepted()) {
                wrappedOut = new GZIPOutputStream(wrappedOut, compressionLevel);
            }

            try (final OutputStream out = wrappedOut) {
                for (final FlowFile flowFile : flowFileList) {
                    session.read(flowFile, new InputStreamCallback() {
                        @Override
                        public void process(final InputStream rawIn) throws IOException {
                            try (final InputStream in = new BufferedInputStream(rawIn)) {

                                FlowFilePackager packager = null;
                                if (!sendAsFlowFile) {
                                    packager = null;
                                } else if (accepts.isFlowFileV3Accepted()) {
                                    packager = new FlowFilePackagerV3();
                                } else if (accepts.isFlowFileV2Accepted()) {
                                    packager = new FlowFilePackagerV2();
                                } else if (accepts.isFlowFileV1Accepted()) {
                                    packager = new FlowFilePackagerV1();
                                }

                                // if none of the above conditions is met, we should never get here, because
                                // we will have already verified that at least 1 of the FlowFile packaging
                                // formats is acceptable if sending as FlowFile.
                                if (packager == null) {
                                    StreamUtils.copy(in, out);
                                } else {
                                    final Map<String, String> flowFileAttributes;
                                    if (isDestinationLegacyNiFi) {
                                        // Old versions of NiFi expect nf.file.name and nf.file.path to indicate filename & path;
                                        // in order to maintain backward compatibility, we copy the filename & path to those attribute keys.
                                        flowFileAttributes = new HashMap<>(flowFile.getAttributes());
                                        flowFileAttributes.put("nf.file.name",
                                                flowFile.getAttribute(CoreAttributes.FILENAME.key()));
                                        flowFileAttributes.put("nf.file.path",
                                                flowFile.getAttribute(CoreAttributes.PATH.key()));
                                    } else {
                                        flowFileAttributes = flowFile.getAttributes();
                                    }

                                    packager.packageFlowFile(in, out, flowFileAttributes, flowFile.getSize());
                                }
                            }
                        }
                    });
                }

                out.flush();
            }
        }
    });

    entity.setChunked(context.getProperty(CHUNKED_ENCODING).asBoolean());
    post.setEntity(entity);
    post.setConfig(requestConfig);

    final String contentType;
    if (sendAsFlowFile) {
        if (accepts.isFlowFileV3Accepted()) {
            contentType = APPLICATION_FLOW_FILE_V3;
        } else if (accepts.isFlowFileV2Accepted()) {
            contentType = APPLICATION_FLOW_FILE_V2;
        } else if (accepts.isFlowFileV1Accepted()) {
            contentType = APPLICATION_FLOW_FILE_V1;
        } else {
            logger.error(
                    "Cannot send data to {} because the destination does not accept FlowFiles and this processor is configured to deliver FlowFiles; rolling back session",
                    new Object[] { url });
            session.rollback();
            context.yield();
            return;
        }
    } else {
        final String attributeValue = toSend.get(0).getAttribute(CoreAttributes.MIME_TYPE.key());
        contentType = (attributeValue == null) ? DEFAULT_CONTENT_TYPE : attributeValue;
    }

    final String attributeHeaderRegex = context.getProperty(ATTRIBUTES_AS_HEADERS_REGEX).getValue();
    if (attributeHeaderRegex != null && !sendAsFlowFile && flowFileList.size() == 1) {
        final Pattern pattern = Pattern.compile(attributeHeaderRegex);

        final Map<String, String> attributes = flowFileList.get(0).getAttributes();
        for (final Map.Entry<String, String> entry : attributes.entrySet()) {
            final String key = entry.getKey();
            if (pattern.matcher(key).matches()) {
                post.setHeader(entry.getKey(), entry.getValue());
            }
        }
    }

    post.setHeader(CONTENT_TYPE, contentType);
    post.setHeader(FLOWFILE_CONFIRMATION_HEADER, "true");
    post.setHeader(PROTOCOL_VERSION_HEADER, PROTOCOL_VERSION);
    post.setHeader(TRANSACTION_ID_HEADER, transactionId);
    if (compressionLevel > 0 && accepts.isGzipAccepted()) {
        post.setHeader(GZIPPED_HEADER, "true");
    }

    // Do the actual POST
    final String flowFileDescription = toSend.size() <= 10 ? toSend.toString() : toSend.size() + " FlowFiles";

    final String uploadDataRate;
    final long uploadMillis;
    CloseableHttpResponse response = null;
    try {
        final StopWatch stopWatch = new StopWatch(true);
        response = client.execute(post);

        // consume input stream entirely, ignoring its contents. If we
        // don't do this, the Connection will not be returned to the pool
        EntityUtils.consume(response.getEntity());
        stopWatch.stop();
        uploadDataRate = stopWatch.calculateDataRate(bytesToSend);
        uploadMillis = stopWatch.getDuration(TimeUnit.MILLISECONDS);
    } catch (final IOException e) {
        logger.error("Failed to Post {} due to {}; transferring to failure",
                new Object[] { flowFileDescription, e });
        context.yield();
        for (FlowFile flowFile : toSend) {
            flowFile = session.penalize(flowFile);
            session.transfer(flowFile, REL_FAILURE);
        }
        return;
    } finally {
        if (response != null) {
            try {
                response.close();
            } catch (IOException e) {
                getLogger().warn("Failed to close HTTP Response due to {}", new Object[] { e });
            }
        }
    }

    // If we get a 'SEE OTHER' status code and an HTTP header that indicates that the intent
    // of the Location URI is a flowfile hold, we will store this holdUri. This prevents us
    // from posting to some other webservice and then attempting to delete some resource to which
    // we are redirected
    final int responseCode = response.getStatusLine().getStatusCode();
    final String responseReason = response.getStatusLine().getReasonPhrase();
    String holdUri = null;
    if (responseCode == HttpServletResponse.SC_SEE_OTHER) {
        final Header locationUriHeader = response.getFirstHeader(LOCATION_URI_INTENT_NAME);
        if (locationUriHeader != null) {
            if (LOCATION_URI_INTENT_VALUE.equals(locationUriHeader.getValue())) {
                final Header holdUriHeader = response.getFirstHeader(LOCATION_HEADER_NAME);
                if (holdUriHeader != null) {
                    holdUri = holdUriHeader.getValue();
                }
            }
        }

        if (holdUri == null) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error(
                        "Failed to Post {} to {}: sent content and received status code {}:{} but no Hold URI",
                        new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }
    }

    if (holdUri == null) {
        if (responseCode == HttpServletResponse.SC_SERVICE_UNAVAILABLE) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error(
                        "Failed to Post {} to {}: response code was {}:{}; will yield processing, since the destination is temporarily unavailable",
                        new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            context.yield();
            return;
        }

        if (responseCode >= 300) {
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                logger.error("Failed to Post {} to {}: response code was {}:{}",
                        new Object[] { flowFile, url, responseCode, responseReason });
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }

        logger.info("Successfully Posted {} to {} in {} at a rate of {}", new Object[] { flowFileDescription,
                url, FormatUtils.formatMinutesSeconds(uploadMillis, TimeUnit.MILLISECONDS), uploadDataRate });

        for (final FlowFile flowFile : toSend) {
            session.getProvenanceReporter().send(flowFile, url, "Remote DN=" + dnHolder.get(), uploadMillis,
                    true);
            session.transfer(flowFile, REL_SUCCESS);
        }
        return;
    }

    //
    // the response indicated a Hold URI; delete the Hold.
    //
    // determine the full URI of the Flow File's Hold; Unfortunately, the responses that are returned have
    // changed over the past, so we have to take into account a few different possibilities.
    String fullHoldUri = holdUri;
    if (holdUri.startsWith("/contentListener")) {
        // If the Hold URI that we get starts with /contentListener, it may not really be /contentListener,
        // as this really indicates that it should be whatever we posted to -- if posting directly to the
        // ListenHTTP component, it will be /contentListener, but if posting to a proxy/load balancer, we may
        // be posting to some other URL.
        fullHoldUri = url + holdUri.substring(16);
    } else if (holdUri.startsWith("/")) {
        // URL indicates the full path but not hostname or port; use the same hostname & port that we posted
        // to but use the full path indicated by the response.
        int firstSlash = url.indexOf("/", 8);
        if (firstSlash < 0) {
            firstSlash = url.length();
        }
        final String beforeSlash = url.substring(0, firstSlash);
        fullHoldUri = beforeSlash + holdUri;
    } else if (!holdUri.startsWith("http")) {
        // Absolute URL
        fullHoldUri = url + (url.endsWith("/") ? "" : "/") + holdUri;
    }

    final HttpDelete delete = new HttpDelete(fullHoldUri);
    delete.setHeader(TRANSACTION_ID_HEADER, transactionId);

    while (true) {
        try {
            final HttpResponse holdResponse = client.execute(delete);
            EntityUtils.consume(holdResponse.getEntity());
            final int holdStatusCode = holdResponse.getStatusLine().getStatusCode();
            final String holdReason = holdResponse.getStatusLine().getReasonPhrase();
            if (holdStatusCode >= 300) {
                logger.error(
                        "Failed to delete Hold that destination placed on {}: got response code {}:{}; routing to failure",
                        new Object[] { flowFileDescription, holdStatusCode, holdReason });

                for (FlowFile flowFile : toSend) {
                    flowFile = session.penalize(flowFile);
                    session.transfer(flowFile, REL_FAILURE);
                }
                return;
            }

            logger.info("Successfully Posted {} to {} in {} milliseconds at a rate of {}",
                    new Object[] { flowFileDescription, url, uploadMillis, uploadDataRate });

            for (FlowFile flowFile : toSend) {
                session.getProvenanceReporter().send(flowFile, url);
                session.transfer(flowFile, REL_SUCCESS);
            }
            return;
        } catch (final IOException e) {
            logger.warn("Failed to delete Hold that destination placed on {} due to {}",
                    new Object[] { flowFileDescription, e });
        }

        if (!isScheduled()) {
            context.yield();
            logger.warn(
                    "Failed to delete Hold that destination placed on {}; Processor has been stopped so routing FlowFile(s) to failure",
                    new Object[] { flowFileDescription });
            for (FlowFile flowFile : toSend) {
                flowFile = session.penalize(flowFile);
                session.transfer(flowFile, REL_FAILURE);
            }
            return;
        }
    }
}