use of org.apache.http.protocol.HttpContext in project nifi by apache.
the class PostHTTP method onTrigger.
@Override
public void onTrigger(final ProcessContext context, final ProcessSession session) {
FlowFile firstFlowFile = session.get();
if (firstFlowFile == null) {
return;
}
final ComponentLog logger = getLogger();
final String url = context.getProperty(URL).evaluateAttributeExpressions(firstFlowFile).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[] { firstFlowFile, url });
firstFlowFile = session.penalize(firstFlowFile);
session.transfer(firstFlowFile, REL_FAILURE);
return;
}
final List<FlowFile> toSend = new ArrayList<>();
toSend.add(firstFlowFile);
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.setSocketTimeout(context.getProperty(DATA_TIMEOUT).asTimePeriod(TimeUnit.MILLISECONDS).intValue());
final RequestConfig requestConfig = requestConfigBuilder.build();
final StreamThrottler throttler = throttlerRef.get();
final Double maxBatchBytes = context.getProperty(MAX_BATCH_SIZE).asDataSize(DataUnit.B);
final AtomicLong bytesToSend = new AtomicLong(firstFlowFile.getSize());
DestinationAccepts destinationAccepts = null;
CloseableHttpClient client = null;
final String transactionId = UUID.randomUUID().toString();
final AtomicReference<String> dnHolder = new AtomicReference<>("none");
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 {
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 Certificate[] certChain = sslSession.getPeerCertificates();
if (certChain == null || certChain.length == 0) {
throw new SSLPeerUnverifiedException("No certificates found");
}
try {
final X509Certificate cert = CertificateUtils.convertAbstractX509Certificate(certChain[0]);
dnHolder.set(cert.getSubjectDN().getName().trim());
} catch (CertificateException e) {
final String msg = "Could not extract subject DN from SSL session peer certificate";
logger.warn(msg);
throw new SSLPeerUnverifiedException(msg);
}
}
}
});
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);
}
// Set the proxy if specified
if (context.getProperty(PROXY_HOST).isSet() && context.getProperty(PROXY_PORT).isSet()) {
final String host = context.getProperty(PROXY_HOST).getValue();
final int port = context.getProperty(PROXY_PORT).asInteger();
clientBuilder.setProxy(new HttpHost(host, port));
}
client = clientBuilder.build();
// determine whether or not destination accepts flowfile/gzip
destinationAccepts = config.getDestinationAccepts();
if (destinationAccepts == null) {
try {
destinationAccepts = getDestinationAcceptance(sendAsFlowFile, client, url, getLogger(), transactionId);
config.setDestinationAccepts(destinationAccepts);
} catch (final IOException e) {
firstFlowFile = session.penalize(firstFlowFile);
session.transfer(firstFlowFile, 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, firstFlowFile, e });
context.yield();
return;
}
}
// then we can get more flowfiles from the session up to MAX_BATCH_SIZE for the same URL
if (sendAsFlowFile && (destinationAccepts.isFlowFileV3Accepted() || destinationAccepts.isFlowFileV2Accepted())) {
toSend.addAll(session.get(new FlowFileFilter() {
@Override
public FlowFileFilterResult filter(FlowFile flowFile) {
// if over MAX_BATCH_SIZE, then stop adding files
if (bytesToSend.get() + flowFile.getSize() > maxBatchBytes) {
return FlowFileFilterResult.REJECT_AND_TERMINATE;
}
// check URL to see if this flowfile can be included in the batch
final String urlToCheck = context.getProperty(URL).evaluateAttributeExpressions(flowFile).getValue();
if (url.equals(urlToCheck)) {
bytesToSend.addAndGet(flowFile.getSize());
return FlowFileFilterResult.ACCEPT_AND_CONTINUE;
} else {
return FlowFileFilterResult.REJECT_AND_CONTINUE;
}
}
}));
}
final HttpPost post = new HttpPost(url);
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 : toSend) {
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();
}
// 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();
}
}
}) {
@Override
public long getContentLength() {
if (compressionLevel == 0 && !sendAsFlowFile && !context.getProperty(CHUNKED_ENCODING).asBoolean()) {
return toSend.get(0).getSize();
} else {
return -1;
}
}
};
if (context.getProperty(CHUNKED_ENCODING).isSet()) {
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();
IOUtils.closeQuietly(client);
return;
}
} else {
final String contentTypeValue = context.getProperty(CONTENT_TYPE).evaluateAttributeExpressions(toSend.get(0)).getValue();
contentType = StringUtils.isBlank(contentTypeValue) ? DEFAULT_CONTENT_TYPE : contentTypeValue;
}
final String attributeHeaderRegex = context.getProperty(ATTRIBUTES_AS_HEADERS_REGEX).getValue();
if (attributeHeaderRegex != null && !sendAsFlowFile && toSend.size() == 1) {
final Pattern pattern = Pattern.compile(attributeHeaderRegex);
final Map<String, String> attributes = toSend.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_HEADER, 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()) {
if (sendAsFlowFile) {
post.setHeader(GZIPPED_HEADER, "true");
} else {
post.setHeader(CONTENT_ENCODING_HEADER, CONTENT_ENCODING_GZIP_VALUE);
}
}
// 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.get());
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;
}
}
}
use of org.apache.http.protocol.HttpContext in project nifi by apache.
the class SiteToSiteRestApiClient method openConnectionForSend.
public void openConnectionForSend(final String transactionUrl, final Peer peer) throws IOException {
final CommunicationsSession commSession = peer.getCommunicationsSession();
final String flowFilesPath = transactionUrl + "/flow-files";
final HttpPost post = createPost(flowFilesPath);
// Set uri so that it'll be used as transit uri.
((HttpCommunicationsSession) peer.getCommunicationsSession()).setDataTransferUrl(post.getURI().toString());
post.setHeader("Content-Type", "application/octet-stream");
post.setHeader("Accept", "text/plain");
post.setHeader(HttpHeaders.PROTOCOL_VERSION, String.valueOf(transportProtocolVersionNegotiator.getVersion()));
setHandshakeProperties(post);
final CountDownLatch initConnectionLatch = new CountDownLatch(1);
final URI requestUri = post.getURI();
final PipedOutputStream outputStream = new PipedOutputStream();
final PipedInputStream inputStream = new PipedInputStream(outputStream, DATA_PACKET_CHANNEL_READ_BUFFER_SIZE);
final ReadableByteChannel dataPacketChannel = Channels.newChannel(inputStream);
final HttpAsyncRequestProducer asyncRequestProducer = new HttpAsyncRequestProducer() {
private final ByteBuffer buffer = ByteBuffer.allocate(DATA_PACKET_CHANNEL_READ_BUFFER_SIZE);
private int totalRead = 0;
private int totalProduced = 0;
private boolean requestHasBeenReset = false;
@Override
public HttpHost getTarget() {
return URIUtils.extractHost(requestUri);
}
@Override
public HttpRequest generateRequest() throws IOException, HttpException {
// Pass the output stream so that Site-to-Site client thread can send
// data packet through this connection.
logger.debug("sending data to {} has started...", flowFilesPath);
((HttpOutput) commSession.getOutput()).setOutputStream(outputStream);
initConnectionLatch.countDown();
final BasicHttpEntity entity = new BasicHttpEntity();
entity.setChunked(true);
entity.setContentType("application/octet-stream");
post.setEntity(entity);
return post;
}
private final AtomicBoolean bufferHasRemainingData = new AtomicBoolean(false);
/**
* If the proxy server requires authentication, the same POST request has to be sent again.
* The first request will result 407, then the next one will be sent with auth headers and actual data.
* This method produces a content only when it's need to be sent, to avoid producing the flow-file contents twice.
* Whether we need to wait auth is determined heuristically by the previous POST request which creates transaction.
* See {@link SiteToSiteRestApiClient#initiateTransactionForSend(HttpPost)} for further detail.
*/
@Override
public void produceContent(final ContentEncoder encoder, final IOControl ioControl) throws IOException {
if (shouldCheckProxyAuth() && proxyAuthRequiresResend.get() && !requestHasBeenReset) {
logger.debug("Need authentication with proxy server. Postpone producing content.");
encoder.complete();
return;
}
if (bufferHasRemainingData.get()) {
// If there's remaining buffer last time, send it first.
writeBuffer(encoder);
if (bufferHasRemainingData.get()) {
return;
}
}
int read;
// or corresponding outputStream is closed.
if ((read = dataPacketChannel.read(buffer)) > -1) {
logger.trace("Read {} bytes from dataPacketChannel. {}", read, flowFilesPath);
totalRead += read;
buffer.flip();
writeBuffer(encoder);
} else {
final long totalWritten = commSession.getOutput().getBytesWritten();
logger.debug("sending data to {} has reached to its end. produced {} bytes by reading {} bytes from channel. {} bytes written in this transaction.", flowFilesPath, totalProduced, totalRead, totalWritten);
if (totalRead != totalWritten || totalProduced != totalWritten) {
final String msg = "Sending data to %s has reached to its end, but produced : read : wrote byte sizes (%d : %d : %d) were not equal. Something went wrong.";
throw new RuntimeException(String.format(msg, flowFilesPath, totalProduced, totalRead, totalWritten));
}
transferDataLatch.countDown();
encoder.complete();
dataPacketChannel.close();
}
}
private void writeBuffer(ContentEncoder encoder) throws IOException {
while (buffer.hasRemaining()) {
final int written = encoder.write(buffer);
logger.trace("written {} bytes to encoder.", written);
if (written == 0) {
logger.trace("Buffer still has remaining. {}", buffer);
bufferHasRemainingData.set(true);
return;
}
totalProduced += written;
}
bufferHasRemainingData.set(false);
buffer.clear();
}
@Override
public void requestCompleted(final HttpContext context) {
logger.debug("Sending data to {} completed.", flowFilesPath);
debugProxyAuthState(context);
}
@Override
public void failed(final Exception ex) {
final String msg = String.format("Failed to send data to %s due to %s", flowFilesPath, ex.toString());
logger.error(msg, ex);
eventReporter.reportEvent(Severity.WARNING, EVENT_CATEGORY, msg);
}
@Override
public boolean isRepeatable() {
// In order to pass authentication, request has to be repeatable.
return true;
}
@Override
public void resetRequest() throws IOException {
logger.debug("Sending data request to {} has been reset...", flowFilesPath);
requestHasBeenReset = true;
}
@Override
public void close() throws IOException {
logger.debug("Closing sending data request to {}", flowFilesPath);
closeSilently(outputStream);
closeSilently(dataPacketChannel);
stopExtendingTtl();
}
};
postResult = getHttpAsyncClient().execute(asyncRequestProducer, new BasicAsyncResponseConsumer(), null);
try {
// Need to wait the post request actually started so that we can write to its output stream.
if (!initConnectionLatch.await(connectTimeoutMillis, TimeUnit.MILLISECONDS)) {
throw new IOException("Awaiting initConnectionLatch has been timeout.");
}
// Started.
transferDataLatch = new CountDownLatch(1);
startExtendingTtl(transactionUrl, dataPacketChannel, null);
} catch (final InterruptedException e) {
throw new IOException("Awaiting initConnectionLatch has been interrupted.", e);
}
}
use of org.apache.http.protocol.HttpContext in project Lucee by lucee.
the class HttpGetWithBody method _doEndTag.
private void _doEndTag() throws PageException, IOException {
long start = System.nanoTime();
HttpClientBuilder builder = HTTPEngine4Impl.getHttpClientBuilder();
ssl(builder);
// redirect
if (redirect)
builder.setRedirectStrategy(new DefaultRedirectStrategy());
else
builder.disableRedirectHandling();
// cookies
BasicCookieStore cookieStore = new BasicCookieStore();
builder.setDefaultCookieStore(cookieStore);
ConfigWeb cw = pageContext.getConfig();
HttpRequestBase req = null;
HttpContext httpContext = null;
CacheHandler cacheHandler = null;
String cacheId = null;
// HttpRequestBase req = init(pageContext.getConfig(),this,client,params,url,port);
{
if (StringUtil.isEmpty(charset, true))
charset = ((PageContextImpl) pageContext).getWebCharset().name();
else
charset = charset.trim();
// check if has fileUploads
boolean doUploadFile = false;
for (int i = 0; i < this.params.size(); i++) {
if ((this.params.get(i)).getType() == HttpParamBean.TYPE_FILE) {
doUploadFile = true;
break;
}
}
// parse url (also query string)
int len = this.params.size();
StringBuilder sbQS = new StringBuilder();
for (int i = 0; i < len; i++) {
HttpParamBean param = this.params.get(i);
int type = param.getType();
// URL
if (type == HttpParamBean.TYPE_URL) {
if (sbQS.length() > 0)
sbQS.append('&');
sbQS.append(param.getEncoded() ? urlenc(param.getName(), charset) : param.getName());
sbQS.append('=');
sbQS.append(param.getEncoded() ? urlenc(param.getValueAsString(), charset) : param.getValueAsString());
}
}
String host = null;
HttpHost httpHost;
try {
URL _url = HTTPUtil.toURL(url, port, encoded);
httpHost = new HttpHost(_url.getHost(), _url.getPort());
host = _url.getHost();
url = _url.toExternalForm();
if (sbQS.length() > 0) {
// no existing QS
if (StringUtil.isEmpty(_url.getQuery())) {
url += "?" + sbQS;
} else {
url += "&" + sbQS;
}
}
} catch (MalformedURLException mue) {
throw Caster.toPageException(mue);
}
// cache
if (cachedWithin != null) {
cacheId = createCacheId();
cacheHandler = pageContext.getConfig().getCacheHandlerCollection(Config.CACHE_TYPE_HTTP, null).getInstanceMatchingObject(cachedWithin, null);
if (cacheHandler instanceof CacheHandlerPro) {
CacheItem cacheItem = ((CacheHandlerPro) cacheHandler).get(pageContext, cacheId, cachedWithin);
if (cacheItem instanceof HTTPCacheItem) {
pageContext.setVariable(result, ((HTTPCacheItem) cacheItem).getData());
return;
}
} else if (cacheHandler != null) {
// TODO this else block can be removed when all cache handlers implement CacheHandlerPro
CacheItem cacheItem = cacheHandler.get(pageContext, cacheId);
if (cacheItem instanceof HTTPCacheItem) {
pageContext.setVariable(result, ((HTTPCacheItem) cacheItem).getData());
return;
}
}
}
// cache not found, process and cache result if needed
// select best matching method (get,post, post multpart (file))
boolean isBinary = false;
boolean doMultiPart = doUploadFile || this.multiPart;
HttpEntityEnclosingRequest eeReqPost = null;
HttpEntityEnclosingRequest eeReq = null;
if (this.method == METHOD_GET) {
req = new HttpGetWithBody(url);
eeReq = (HttpEntityEnclosingRequest) req;
} else if (this.method == METHOD_HEAD) {
req = new HttpHead(url);
} else if (this.method == METHOD_DELETE) {
isBinary = true;
req = new HttpDeleteWithBody(url);
eeReq = (HttpEntityEnclosingRequest) req;
} else if (this.method == METHOD_PUT) {
isBinary = true;
HttpPut put = new HttpPut(url);
eeReqPost = put;
req = put;
eeReq = put;
} else if (this.method == METHOD_TRACE) {
isBinary = true;
req = new HttpTrace(url);
} else if (this.method == METHOD_OPTIONS) {
isBinary = true;
req = new HttpOptions(url);
} else if (this.method == METHOD_PATCH) {
isBinary = true;
eeReq = HTTPPatchFactory.getHTTPPatch(url);
req = (HttpRequestBase) eeReq;
} else {
isBinary = true;
eeReqPost = new HttpPost(url);
req = (HttpPost) eeReqPost;
eeReq = eeReqPost;
}
boolean hasForm = false;
boolean hasBody = false;
boolean hasContentType = false;
// Set http params
ArrayList<FormBodyPart> parts = new ArrayList<FormBodyPart>();
StringBuilder acceptEncoding = new StringBuilder();
java.util.List<NameValuePair> postParam = eeReqPost != null ? new ArrayList<NameValuePair>() : null;
for (int i = 0; i < len; i++) {
HttpParamBean param = this.params.get(i);
int type = param.getType();
// URL
if (type == HttpParamBean.TYPE_URL) {
// listQS.add(new BasicNameValuePair(translateEncoding(param.getName(), http.charset),translateEncoding(param.getValueAsString(),
// http.charset)));
} else // Form
if (type == HttpParamBean.TYPE_FORM) {
hasForm = true;
if (this.method == METHOD_GET)
throw new ApplicationException("httpparam with type formfield can only be used when the method attribute of the parent http tag is set to post");
if (eeReqPost != null) {
if (doMultiPart) {
parts.add(new FormBodyPart(param.getName(), new StringBody(param.getValueAsString(), CharsetUtil.toCharset(charset))));
} else {
postParam.add(new BasicNameValuePair(param.getName(), param.getValueAsString()));
}
}
// else if(multi!=null)multi.addParameter(param.getName(),param.getValueAsString());
} else // CGI
if (type == HttpParamBean.TYPE_CGI) {
if (param.getEncoded())
req.addHeader(urlenc(param.getName(), charset), urlenc(param.getValueAsString(), charset));
else
req.addHeader(param.getName(), param.getValueAsString());
} else // Header
if (type == HttpParamBean.TYPE_HEADER) {
if (param.getName().equalsIgnoreCase("content-type"))
hasContentType = true;
if (param.getName().equalsIgnoreCase("Content-Length")) {
} else if (param.getName().equalsIgnoreCase("Accept-Encoding")) {
acceptEncoding.append(headerValue(param.getValueAsString()));
acceptEncoding.append(", ");
} else
req.addHeader(param.getName(), headerValue(param.getValueAsString()));
} else // Cookie
if (type == HttpParamBean.TYPE_COOKIE) {
HTTPEngine4Impl.addCookie(cookieStore, host, param.getName(), param.getValueAsString(), "/", charset);
} else // File
if (type == HttpParamBean.TYPE_FILE) {
hasForm = true;
if (this.method == METHOD_GET)
throw new ApplicationException("httpparam type file can't only be used, when method of the tag http equal post");
// if(param.getFile()==null) throw new ApplicationException("httpparam type file can't only be used, when method of the tag http equal
// post");
String strCT = getContentType(param);
ContentType ct = HTTPUtil.toContentType(strCT, null);
String mt = "text/xml";
if (ct != null && !StringUtil.isEmpty(ct.getMimeType(), true))
mt = ct.getMimeType();
String cs = charset;
if (ct != null && !StringUtil.isEmpty(ct.getCharset(), true))
cs = ct.getCharset();
if (doMultiPart) {
try {
Resource res = param.getFile();
parts.add(new FormBodyPart(param.getName(), new ResourceBody(res, mt, res.getName(), cs)));
// parts.add(new ResourcePart(param.getName(),new ResourcePartSource(param.getFile()),getContentType(param),_charset));
} catch (FileNotFoundException e) {
throw new ApplicationException("can't upload file, path is invalid", e.getMessage());
}
}
} else // XML
if (type == HttpParamBean.TYPE_XML) {
ContentType ct = HTTPUtil.toContentType(param.getMimeType(), null);
String mt = "text/xml";
if (ct != null && !StringUtil.isEmpty(ct.getMimeType(), true))
mt = ct.getMimeType();
String cs = charset;
if (ct != null && !StringUtil.isEmpty(ct.getCharset(), true))
cs = ct.getCharset();
hasBody = true;
hasContentType = true;
req.addHeader("Content-type", mt + "; charset=" + cs);
if (eeReq == null)
throw new ApplicationException("type xml is only supported for methods get, delete, post, and put");
HTTPEngine4Impl.setBody(eeReq, param.getValueAsString(), mt, cs);
} else // Body
if (type == HttpParamBean.TYPE_BODY) {
ContentType ct = HTTPUtil.toContentType(param.getMimeType(), null);
String mt = null;
if (ct != null && !StringUtil.isEmpty(ct.getMimeType(), true))
mt = ct.getMimeType();
String cs = charset;
if (ct != null && !StringUtil.isEmpty(ct.getCharset(), true))
cs = ct.getCharset();
hasBody = true;
if (eeReq == null)
throw new ApplicationException("type body is only supported for methods get, delete, post, and put");
HTTPEngine4Impl.setBody(eeReq, param.getValue(), mt, cs);
} else {
throw new ApplicationException("invalid type [" + type + "]");
}
}
// post params
if (postParam != null && postParam.size() > 0)
eeReqPost.setEntity(new org.apache.http.client.entity.UrlEncodedFormEntity(postParam, charset));
if (compression) {
acceptEncoding.append("gzip");
} else {
acceptEncoding.append("deflate;q=0");
req.setHeader("TE", "deflate;q=0");
}
req.setHeader("Accept-Encoding", acceptEncoding.toString());
// multipart
if (doMultiPart && eeReq != null) {
hasContentType = true;
boolean doIt = true;
if (!this.multiPart && parts.size() == 1) {
ContentBody body = parts.get(0).getBody();
if (body instanceof StringBody) {
StringBody sb = (StringBody) body;
try {
org.apache.http.entity.ContentType ct = org.apache.http.entity.ContentType.create(sb.getMimeType(), sb.getCharset());
String str = IOUtil.toString(sb.getReader());
StringEntity entity = new StringEntity(str, ct);
eeReq.setEntity(entity);
} catch (IOException e) {
throw Caster.toPageException(e);
}
doIt = false;
}
}
if (doIt) {
MultipartEntityBuilder mpeBuilder = MultipartEntityBuilder.create().setStrictMode();
// enabling the line below will append charset=... to the Content-Type header
// if (!StringUtil.isEmpty(charset, true))
// mpeBuilder.setCharset(CharsetUtil.toCharset(charset));
Iterator<FormBodyPart> it = parts.iterator();
while (it.hasNext()) {
FormBodyPart part = it.next();
mpeBuilder.addPart(part);
}
eeReq.setEntity(mpeBuilder.build());
}
// eem.setRequestEntity(new MultipartRequestEntityFlex(parts.toArray(new Part[parts.size()]), eem.getParams(),http.multiPartType));
}
if (hasBody && hasForm)
throw new ApplicationException("mixing httpparam type file/formfield and body/XML is not allowed");
if (!hasContentType) {
if (isBinary) {
if (hasBody)
req.addHeader("Content-type", "application/octet-stream");
else
req.addHeader("Content-type", "application/x-www-form-urlencoded; charset=" + charset);
} else {
if (hasBody)
req.addHeader("Content-type", "text/html; charset=" + charset);
}
}
// set User Agent
if (!hasHeaderIgnoreCase(req, "User-Agent"))
req.setHeader("User-Agent", this.useragent);
// set timeout
setTimeout(builder, checkRemainingTimeout());
// set Username and Password
if (this.username != null) {
if (this.password == null)
this.password = "";
if (AUTH_TYPE_NTLM == this.authType) {
if (StringUtil.isEmpty(this.workStation, true))
throw new ApplicationException("attribute workstation is required when authentication type is [NTLM]");
if (StringUtil.isEmpty(this.domain, true))
throw new ApplicationException("attribute domain is required when authentication type is [NTLM]");
HTTPEngine4Impl.setNTCredentials(builder, this.username, this.password, this.workStation, this.domain);
} else
httpContext = HTTPEngine4Impl.setCredentials(builder, httpHost, this.username, this.password, preauth);
}
// set Proxy
ProxyData proxy = null;
if (!StringUtil.isEmpty(this.proxyserver)) {
proxy = ProxyDataImpl.getInstance(this.proxyserver, this.proxyport, this.proxyuser, this.proxypassword);
}
if (pageContext.getConfig().isProxyEnableFor(host)) {
proxy = pageContext.getConfig().getProxyData();
}
HTTPEngine4Impl.setProxy(builder, req, proxy);
}
CloseableHttpClient client = null;
try {
if (httpContext == null)
httpContext = new BasicHttpContext();
Struct cfhttp = new StructImpl();
cfhttp.setEL(ERROR_DETAIL, "");
pageContext.setVariable(result, cfhttp);
// ///////////////////////////////////////// EXECUTE /////////////////////////////////////////////////
client = builder.build();
Executor4 e = new Executor4(pageContext, this, client, httpContext, req, redirect);
HTTPResponse4Impl rsp = null;
if (timeout == null || timeout.getMillis() <= 0) {
try {
rsp = e.execute(httpContext);
} catch (Throwable t) {
ExceptionUtil.rethrowIfNecessary(t);
if (!throwonerror) {
if (t instanceof SocketTimeoutException)
setRequestTimeout(cfhttp);
else
setUnknownHost(cfhttp, t);
return;
}
throw toPageException(t, rsp);
}
} else {
e.start();
try {
synchronized (this) {
// print.err(timeout);
this.wait(timeout.getMillis());
}
} catch (InterruptedException ie) {
throw Caster.toPageException(ie);
}
if (e.t != null) {
if (!throwonerror) {
setUnknownHost(cfhttp, e.t);
return;
}
throw toPageException(e.t, rsp);
}
rsp = e.response;
if (!e.done) {
req.abort();
if (throwonerror)
throw new HTTPException("408 Request Time-out", "a timeout occurred in tag http", 408, "Time-out", rsp == null ? null : rsp.getURL());
setRequestTimeout(cfhttp);
return;
// throw new ApplicationException("timeout");
}
}
// ///////////////////////////////////////// EXECUTE /////////////////////////////////////////////////
Charset responseCharset = CharsetUtil.toCharset(rsp.getCharset());
int statCode = 0;
// Write Response Scope
// String rawHeader=httpMethod.getStatusLine().toString();
String mimetype = null;
String contentEncoding = null;
// status code
cfhttp.set(STATUSCODE, ((rsp.getStatusCode() + " " + rsp.getStatusText()).trim()));
cfhttp.set(STATUS_CODE, new Double(statCode = rsp.getStatusCode()));
cfhttp.set(STATUS_TEXT, (rsp.getStatusText()));
cfhttp.set(HTTP_VERSION, (rsp.getProtocolVersion()));
// responseHeader
lucee.commons.net.http.Header[] headers = rsp.getAllHeaders();
StringBuffer raw = new StringBuffer(rsp.getStatusLine() + " ");
Struct responseHeader = new StructImpl();
Struct cookie;
Array setCookie = new ArrayImpl();
Query cookies = new QueryImpl(new String[] { "name", "value", "path", "domain", "expires", "secure", "httpOnly" }, 0, "cookies");
for (int i = 0; i < headers.length; i++) {
lucee.commons.net.http.Header header = headers[i];
// print.ln(header);
raw.append(header.toString() + " ");
if (header.getName().equalsIgnoreCase("Set-Cookie")) {
setCookie.append(header.getValue());
parseCookie(cookies, header.getValue());
} else {
// print.ln(header.getName()+"-"+header.getValue());
Object value = responseHeader.get(KeyImpl.getInstance(header.getName()), null);
if (value == null)
responseHeader.set(KeyImpl.getInstance(header.getName()), header.getValue());
else {
Array arr = null;
if (value instanceof Array) {
arr = (Array) value;
} else {
arr = new ArrayImpl();
responseHeader.set(KeyImpl.getInstance(header.getName()), arr);
arr.appendEL(value);
}
arr.appendEL(header.getValue());
}
}
// Content-Type
if (header.getName().equalsIgnoreCase("Content-Type")) {
mimetype = header.getValue();
if (mimetype == null)
mimetype = NO_MIMETYPE;
}
// Content-Encoding
if (header.getName().equalsIgnoreCase("Content-Encoding")) {
contentEncoding = header.getValue();
}
}
cfhttp.set(RESPONSEHEADER, responseHeader);
cfhttp.set(KeyConstants._cookies, cookies);
responseHeader.set(STATUS_CODE, new Double(statCode = rsp.getStatusCode()));
responseHeader.set(EXPLANATION, (rsp.getStatusText()));
if (setCookie.size() > 0)
responseHeader.set(SET_COOKIE, setCookie);
// is text
boolean isText = mimetype == null || mimetype == NO_MIMETYPE || HTTPUtil.isTextMimeType(mimetype);
// is multipart
boolean isMultipart = MultiPartResponseUtils.isMultipart(mimetype);
cfhttp.set(KeyConstants._text, Caster.toBoolean(isText));
// boolean responseProvideCharset=false;
if (!StringUtil.isEmpty(mimetype, true)) {
if (isText) {
String[] types = HTTPUtil.splitMimeTypeAndCharset(mimetype, null);
if (types[0] != null)
cfhttp.set(KeyConstants._mimetype, types[0]);
if (types[1] != null)
cfhttp.set(CHARSET, types[1]);
} else
cfhttp.set(KeyConstants._mimetype, mimetype);
} else
cfhttp.set(KeyConstants._mimetype, NO_MIMETYPE);
// File
Resource file = null;
if (strFile != null && strPath != null) {
file = ResourceUtil.toResourceNotExisting(pageContext, strPath).getRealResource(strFile);
} else if (strFile != null) {
file = ResourceUtil.toResourceNotExisting(pageContext, strFile);
} else if (strPath != null) {
file = ResourceUtil.toResourceNotExisting(pageContext, strPath);
// Resource dir = file.getParentResource();
if (file.isDirectory()) {
// TODO was getName()
file = file.getRealResource(req.getURI().getPath());
// ->http://hc.apache.org/httpclient-3.x/apidocs/org/apache/commons/httpclient/URI.html#getName()
}
}
if (file != null)
pageContext.getConfig().getSecurityManager().checkFileLocation(file);
// filecontent
InputStream is = null;
if (isText && getAsBinary != GET_AS_BINARY_YES) {
String str;
try {
// read content
if (method != METHOD_HEAD) {
is = rsp.getContentAsStream();
if (is != null && isGzipEncoded(contentEncoding))
is = rsp.getStatusCode() != 200 ? new CachingGZIPInputStream(is) : new GZIPInputStream(is);
}
try {
try {
str = is == null ? "" : IOUtil.toString(is, responseCharset, checkRemainingTimeout().getMillis());
} catch (EOFException eof) {
if (is instanceof CachingGZIPInputStream) {
str = IOUtil.toString(is = ((CachingGZIPInputStream) is).getRawData(), responseCharset, checkRemainingTimeout().getMillis());
} else
throw eof;
}
} catch (UnsupportedEncodingException uee) {
str = IOUtil.toString(is, (Charset) null, checkRemainingTimeout().getMillis());
}
} catch (IOException ioe) {
throw Caster.toPageException(ioe);
} finally {
IOUtil.closeEL(is);
}
if (str == null)
str = "";
if (resolveurl) {
// if(e.redirectURL!=null)url=e.redirectURL.toExternalForm();
str = new URLResolver().transform(str, e.response.getTargetURL(), false);
}
cfhttp.set(KeyConstants._filecontent, str);
try {
if (file != null) {
IOUtil.write(file, str, ((PageContextImpl) pageContext).getWebCharset(), false);
}
} catch (IOException e1) {
}
if (name != null) {
Query qry = CSVParser.toQuery(str, delimiter, textqualifier, columns, firstrowasheaders);
pageContext.setVariable(name, qry);
}
} else // Binary
{
byte[] barr = null;
if (isGzipEncoded(contentEncoding)) {
if (method != METHOD_HEAD) {
is = rsp.getContentAsStream();
is = rsp.getStatusCode() != 200 ? new CachingGZIPInputStream(is) : new GZIPInputStream(is);
}
try {
try {
barr = is == null ? new byte[0] : IOUtil.toBytes(is);
} catch (EOFException eof) {
if (is instanceof CachingGZIPInputStream)
barr = IOUtil.toBytes(((CachingGZIPInputStream) is).getRawData());
else
throw eof;
}
} catch (IOException t) {
throw Caster.toPageException(t);
} finally {
IOUtil.closeEL(is);
}
} else {
try {
if (method != METHOD_HEAD)
barr = rsp.getContentAsByteArray();
else
barr = new byte[0];
} catch (IOException t) {
throw Caster.toPageException(t);
}
}
// IF Multipart response get file content and parse parts
if (barr != null) {
if (isMultipart) {
cfhttp.set(KeyConstants._filecontent, MultiPartResponseUtils.getParts(barr, mimetype));
} else {
cfhttp.set(KeyConstants._filecontent, barr);
}
} else
cfhttp.set(KeyConstants._filecontent, "");
if (file != null) {
try {
if (barr != null)
IOUtil.copy(new ByteArrayInputStream(barr), file, true);
} catch (IOException ioe) {
throw Caster.toPageException(ioe);
}
}
}
// header
cfhttp.set(KeyConstants._header, raw.toString());
if (!isStatusOK(rsp.getStatusCode())) {
String msg = rsp.getStatusCode() + " " + rsp.getStatusText();
cfhttp.setEL(ERROR_DETAIL, msg);
if (throwonerror) {
throw new HTTPException(msg, null, rsp.getStatusCode(), rsp.getStatusText(), rsp.getURL());
}
}
// TODO: check if we can use statCode instead of rsp.getStatusCode() everywhere and cleanup the code
if (cacheHandler != null && rsp.getStatusCode() == 200) {
// add to cache
cacheHandler.set(pageContext, cacheId, cachedWithin, new HTTPCacheItem(cfhttp, url, System.nanoTime() - start));
}
} finally {
if (client != null)
client.close();
}
}
use of org.apache.http.protocol.HttpContext in project Lucee by lucee.
the class HTTPEngine4Impl method _invoke.
private static HTTPResponse _invoke(URL url, HttpUriRequest request, String username, String password, long timeout, boolean redirect, String charset, String useragent, ProxyData proxy, lucee.commons.net.http.Header[] headers, Map<String, String> formfields) throws IOException {
HttpClientBuilder builder = getHttpClientBuilder();
// redirect
if (redirect)
builder.setRedirectStrategy(new DefaultRedirectStrategy());
else
builder.disableRedirectHandling();
HttpHost hh = new HttpHost(url.getHost(), url.getPort());
setHeader(request, headers);
if (CollectionUtil.isEmpty(formfields))
setContentType(request, charset);
setFormFields(request, formfields, charset);
setUserAgent(request, useragent);
if (timeout > 0)
Http.setTimeout(builder, TimeSpanImpl.fromMillis(timeout));
HttpContext context = setCredentials(builder, hh, username, password, false);
setProxy(builder, request, proxy);
CloseableHttpClient client = builder.build();
if (context == null)
context = new BasicHttpContext();
return new HTTPResponse4Impl(url, context, request, client.execute(request, context));
}
use of org.apache.http.protocol.HttpContext in project uavstack by uavorg.
the class ApacheAsyncHttpClientIT method doAsyncStart.
/**
* for async http client
*
* @param args
* @return
*/
@SuppressWarnings({ "rawtypes", "unused", "unchecked" })
public FutureCallback doAsyncStart(Object[] args) {
HttpAsyncRequestProducer requestProducer = null;
HttpAsyncResponseConsumer responseConsumer = null;
HttpContext context = null;
FutureCallback callback = null;
Map mObj = null;
if (args.length == 4) {
requestProducer = (HttpAsyncRequestProducer) args[0];
responseConsumer = (HttpAsyncResponseConsumer) args[1];
context = (HttpContext) args[2];
callback = (FutureCallback) args[3];
} else if (args.length == 5) {
requestProducer = (HttpAsyncRequestProducer) args[1];
responseConsumer = (HttpAsyncResponseConsumer) args[2];
context = (HttpContext) args[3];
callback = (FutureCallback) args[4];
}
String httpAction = null;
try {
HttpRequest hr = requestProducer.generateRequest();
/**
* 呵呵,就是把UAV的客户端标记加到http header里面,接收方就知道是哪个东东调用的了,便于实现来源快速匹配,这个模式只适合直连模式
*
* 对于代理模式,只匹配代理源即可
*/
hr.addHeader("UAV-Client-Src", MonitorServerUtil.getUAVClientSrc(this.applicationId));
RequestLine rl = hr.getRequestLine();
httpAction = rl.getMethod();
targetURL = rl.getUri();
} catch (IOException e) {
// ignore thie exception
return null;
} catch (HttpException e) {
// ignore thie exception
return null;
}
Map<String, Object> params = new HashMap<String, Object>();
params.put(CaptureConstants.INFO_CLIENT_REQUEST_URL, targetURL);
params.put(CaptureConstants.INFO_CLIENT_REQUEST_ACTION, httpAction);
params.put(CaptureConstants.INFO_CLIENT_APPID, this.applicationId);
params.put(CaptureConstants.INFO_CLIENT_TYPE, "apache.http.AsyncClient");
if (logger.isDebugable()) {
logger.debug("Invoke START:" + targetURL + "," + httpAction + "," + this.applicationId, null);
}
/**
* for async, as not in the same thread
*/
ccMap = UAVServer.instance().runMonitorAsyncCaptureOnServerCapPoint(CaptureConstants.CAPPOINT_APP_CLIENT, Monitor.CapturePhase.PRECAP, params, null);
// register invokechain adapter
UAVServer.instance().runSupporter("com.creditease.uav.apm.supporters.InvokeChainSupporter", "registerAdapter", ApacheAsyncHttpClientAdapter.class);
ccMap4Chain = (Map<String, Object>) UAVServer.instance().runSupporter("com.creditease.uav.apm.supporters.InvokeChainSupporter", "runCap", InvokeChainConstants.CHAIN_APP_CLIENT, InvokeChainConstants.CapturePhase.PRECAP, params, ApacheAsyncHttpClientAdapter.class, args);
if (callback == null) {
return null;
}
callback = JDKProxyInvokeUtil.newProxyInstance(HttpContext.class.getClassLoader(), new Class<?>[] { FutureCallback.class }, new JDKProxyInvokeHandler<FutureCallback>(callback, new FutureCallbackProxyInvokeProcessor(ccMap4Chain)));
return callback;
}
Aggregations