use of org.apache.http.nio.NHttpServerConnection in project wso2-synapse by wso2.
the class TargetHandler method responseReceived.
public void responseReceived(NHttpClientConnection conn) {
HttpContext context = conn.getContext();
if (isMessageSizeValidationEnabled) {
context.setAttribute(PassThroughConstants.MESSAGE_SIZE_VALIDATION_SUM, 0);
}
HttpResponse response = conn.getHttpResponse();
ProtocolState connState;
try {
String method = null;
ProxyTunnelHandler tunnelHandler = (ProxyTunnelHandler) context.getAttribute(PassThroughConstants.TUNNEL_HANDLER);
if (tunnelHandler != null && !tunnelHandler.isCompleted()) {
method = "CONNECT";
context.removeAttribute(PassThroughConstants.TUNNEL_HANDLER);
tunnelHandler.handleResponse(response, conn);
if (tunnelHandler.isSuccessful()) {
log.debug(conn + ": Tunnel established");
conn.resetInput();
conn.requestOutput();
return;
} else {
log.warn("Tunnel response failed");
// the reason for getting the targetRequest and calling the consumeError() on pipe. Instead of
// calling the informWriterError(NHTTPClientConnection) is, at this point the
// "writeCondition.await()" is already called but the corresponding pipe is not yet set as
// a writer in TargetContext
TargetRequest targetRequest = TargetContext.getRequest(conn);
if (targetRequest != null) {
targetRequest.getPipe().consumerError();
} else {
log.warn("Failed target response, but the target request is null");
}
TargetContext.updateState(conn, ProtocolState.REQUEST_DONE);
}
}
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode < HttpStatus.SC_OK) {
if (log.isDebugEnabled()) {
log.debug(conn + ": Received a 100 Continue response");
}
// Ignore 1xx response
return;
}
boolean isError = false;
context.setAttribute(PassThroughConstants.RES_HEADER_ARRIVAL_TIME, System.currentTimeMillis());
connState = TargetContext.getState(conn);
MessageContext requestMsgContext = TargetContext.get(conn).getRequestMsgCtx();
NHttpServerConnection sourceConn = (NHttpServerConnection) requestMsgContext.getProperty(PassThroughConstants.PASS_THROUGH_SOURCE_CONNECTION);
if (connState != ProtocolState.REQUEST_DONE) {
isError = true;
// State is not REQUEST_DONE. i.e the request is not completely written. But the response is started
// receiving, therefore informing a write error has occurred. So the thread which is
// waiting on writing the request out, will get notified.
informWriterError(conn);
StatusLine errorStatus = response.getStatusLine();
/* We might receive a 404 or a similar type, even before we write the request body. */
if (errorStatus != null) {
if (errorStatus.getStatusCode() >= HttpStatus.SC_BAD_REQUEST) {
TargetContext.updateState(conn, ProtocolState.REQUEST_DONE);
conn.resetOutput();
if (sourceConn != null) {
SourceContext.updateState(sourceConn, ProtocolState.REQUEST_DONE);
SourceContext.get(sourceConn).setShutDown(true);
}
if (log.isDebugEnabled()) {
log.debug(conn + ": Received response with status code : " + response.getStatusLine().getStatusCode() + " in invalid state : " + connState.name());
}
}
} else {
handleInvalidState(conn, "Receiving response");
return;
}
}
context.setAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_START_TIME, System.currentTimeMillis());
TargetRequest targetRequest = TargetContext.getRequest(conn);
if (targetRequest != null) {
method = targetRequest.getMethod();
}
if (method == null) {
method = "POST";
}
boolean canResponseHaveBody = isResponseHaveBodyExpected(method, response);
if (!canResponseHaveBody) {
if (log.isDebugEnabled()) {
log.debug(conn + ": Received no-content response " + response.getStatusLine().getStatusCode());
}
conn.resetInput();
}
TargetResponse targetResponse = new TargetResponse(targetConfiguration, response, conn, canResponseHaveBody, isError);
TargetContext.setResponse(conn, targetResponse);
targetResponse.start(conn);
if (statusCode == HttpStatus.SC_ACCEPTED && handle202(requestMsgContext)) {
return;
}
targetConfiguration.getWorkerPool().execute(new ClientWorker(targetConfiguration, requestMsgContext, targetResponse));
targetConfiguration.getMetrics().incrementMessagesReceived();
sourceConn = (NHttpServerConnection) requestMsgContext.getProperty(PassThroughConstants.PASS_THROUGH_SOURCE_CONNECTION);
if (sourceConn != null) {
sourceConn.getContext().setAttribute(PassThroughConstants.RES_HEADER_ARRIVAL_TIME, conn.getContext().getAttribute(PassThroughConstants.RES_HEADER_ARRIVAL_TIME));
conn.getContext().removeAttribute(PassThroughConstants.RES_HEADER_ARRIVAL_TIME);
sourceConn.getContext().setAttribute(PassThroughConstants.REQ_DEPARTURE_TIME, conn.getContext().getAttribute(PassThroughConstants.REQ_DEPARTURE_TIME));
conn.getContext().removeAttribute(PassThroughConstants.REQ_DEPARTURE_TIME);
sourceConn.getContext().setAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_START_TIME, conn.getContext().getAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_START_TIME));
conn.getContext().removeAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_START_TIME);
sourceConn.getContext().setAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_END_TIME, conn.getContext().getAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_END_TIME));
conn.getContext().removeAttribute(PassThroughConstants.REQ_TO_BACKEND_WRITE_END_TIME);
sourceConn.getContext().setAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_START_TIME, conn.getContext().getAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_START_TIME));
conn.getContext().removeAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_START_TIME);
}
} catch (Exception ex) {
log.error("Exception occurred while processing response", ex);
informReaderError(conn);
TargetContext.updateState(conn, ProtocolState.CLOSED);
targetConfiguration.getConnections().shutdownConnection(conn, true);
}
}
use of org.apache.http.nio.NHttpServerConnection in project wso2-synapse by wso2.
the class TargetHandler method inputReady.
public void inputReady(NHttpClientConnection conn, ContentDecoder decoder) {
ProtocolState connState;
MessageContext msgCtx = TargetContext.get(conn).getRequestMsgCtx();
try {
connState = TargetContext.getState(conn);
if (connState.compareTo(ProtocolState.RESPONSE_HEAD) < 0) {
return;
}
if (connState != ProtocolState.RESPONSE_HEAD && connState != ProtocolState.RESPONSE_BODY) {
handleInvalidState(conn, "Response received");
return;
}
TargetContext.updateState(conn, ProtocolState.RESPONSE_BODY);
TargetResponse response = TargetContext.getResponse(conn);
int statusCode = -1;
if (response != null) {
statusCode = conn.getHttpResponse().getStatusLine().getStatusCode();
int responseRead = response.read(conn, decoder);
if (isMessageSizeValidationEnabled) {
HttpContext httpContext = conn.getContext();
// method responseReceived()
if (httpContext.getAttribute(PassThroughConstants.MESSAGE_SIZE_VALIDATION_SUM) == null) {
httpContext.setAttribute(PassThroughConstants.MESSAGE_SIZE_VALIDATION_SUM, 0);
}
int messageSizeSum = (int) httpContext.getAttribute(PassThroughConstants.MESSAGE_SIZE_VALIDATION_SUM);
messageSizeSum += responseRead;
if (messageSizeSum > validMaxMessageSize) {
log.warn("Payload exceeds valid payload size range, hence discontinuing chunk stream at " + messageSizeSum + " bytes to prevent OOM.");
dropTargetConnection(conn);
response.getPipe().forceProducerComplete(decoder);
}
httpContext.setAttribute(PassThroughConstants.MESSAGE_SIZE_VALIDATION_SUM, messageSizeSum);
}
if (metrics.getLevel() == MetricsCollector.LEVEL_FULL) {
metrics.incrementBytesReceived(msgCtx, responseRead);
} else {
metrics.incrementBytesReceived(responseRead);
}
}
if (decoder.isCompleted()) {
if (metrics.getLevel() == MetricsCollector.LEVEL_FULL) {
metrics.incrementMessagesReceived(msgCtx);
metrics.notifyReceivedMessageSize(msgCtx, conn.getMetrics().getReceivedBytesCount());
metrics.notifySentMessageSize(msgCtx, conn.getMetrics().getSentBytesCount());
if (statusCode != -1) {
metrics.reportResponseCode(msgCtx, statusCode);
}
} else {
metrics.incrementMessagesReceived();
metrics.notifyReceivedMessageSize(conn.getMetrics().getReceivedBytesCount());
metrics.notifySentMessageSize(conn.getMetrics().getSentBytesCount());
}
MessageContext requestMsgContext = TargetContext.get(conn).getRequestMsgCtx();
NHttpServerConnection sourceConn = (NHttpServerConnection) requestMsgContext.getProperty(PassThroughConstants.PASS_THROUGH_SOURCE_CONNECTION);
if (sourceConn != null) {
if (conn.getContext().getAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_END_TIME) != null) {
sourceConn.getContext().setAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_END_TIME, conn.getContext().getAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_END_TIME));
conn.getContext().removeAttribute(PassThroughConstants.RES_FROM_BACKEND_READ_END_TIME);
}
sourceConn.getContext().setAttribute(PassThroughConstants.RES_ARRIVAL_TIME, conn.getContext().getAttribute(PassThroughConstants.RES_ARRIVAL_TIME));
conn.getContext().removeAttribute(PassThroughConstants.RES_ARRIVAL_TIME);
}
}
} catch (IOException e) {
logIOException(conn, e);
informReaderError(conn);
TargetContext.updateState(conn, ProtocolState.CLOSED);
targetConfiguration.getConnections().shutdownConnection(conn, true);
} catch (Exception ex) {
log.error("Exception occurred while reading request body", ex);
informReaderError(conn);
TargetContext.updateState(conn, ProtocolState.CLOSED);
targetConfiguration.getConnections().shutdownConnection(conn, true);
}
}
use of org.apache.http.nio.NHttpServerConnection in project wso2-synapse by wso2.
the class PassThroughHttpSender method submitResponse.
public void submitResponse(MessageContext msgContext) throws IOException, HttpException {
SourceConfiguration sourceConfiguration = (SourceConfiguration) msgContext.getProperty(PassThroughConstants.PASS_THROUGH_SOURCE_CONFIGURATION);
NHttpServerConnection conn = (NHttpServerConnection) msgContext.getProperty(PassThroughConstants.PASS_THROUGH_SOURCE_CONNECTION);
if (conn == null) {
ServerWorker serverWorker = (ServerWorker) msgContext.getProperty(Constants.OUT_TRANSPORT_INFO);
if (serverWorker != null) {
MessageContext requestContext = serverWorker.getRequestContext();
conn = (NHttpServerConnection) requestContext.getProperty(PassThroughConstants.PASS_THROUGH_SOURCE_CONNECTION);
sourceConfiguration = (SourceConfiguration) requestContext.getProperty(PassThroughConstants.PASS_THROUGH_SOURCE_CONFIGURATION);
} else {
throw new IllegalStateException("Unable to correlate the response to a request");
}
}
// Handle ETag caching
if (msgContext.getProperty(PassThroughConstants.HTTP_ETAG_ENABLED) != null && (Boolean) msgContext.getProperty(PassThroughConstants.HTTP_ETAG_ENABLED)) {
try {
RelayUtils.buildMessage(msgContext);
} catch (IOException e) {
handleException("IO Error occurred while building the message", e);
} catch (XMLStreamException e) {
handleException("XML Error occurred while building the message", e);
}
String hash = digestGenerator.getDigest(msgContext);
Map headers = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
headers.put(HttpHeaders.ETAG, "\"" + hash + "\"");
}
if (msgContext.getProperty(Constants.Configuration.ENABLE_MTOM) != null && !Boolean.TRUE.equals(msgContext.getProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED))) {
try {
RelayUtils.buildMessage(msgContext);
} catch (IOException e) {
handleException("IO Error occurred while building the message", e);
} catch (XMLStreamException e) {
handleException("XML Error occurred while building the message", e);
}
}
SourceRequest sourceRequest = SourceContext.getRequest(conn);
if (sourceRequest == null) {
// this is a special case we dropped source connection where message size exceeds the user defined threshold
if (conn.getContext().getAttribute(PassThroughConstants.SOURCE_CONNECTION_DROPPED) != null && (Boolean) conn.getContext().getAttribute(PassThroughConstants.SOURCE_CONNECTION_DROPPED)) {
// already submitted response for this case, hence return
return;
}
log.warn("Trying to submit a response to an already closed connection : " + conn);
return;
}
SourceResponse sourceResponse = SourceResponseFactory.create(msgContext, sourceRequest, sourceConfiguration);
sourceResponse.checkResponseChunkDisable(msgContext);
SourceContext.setResponse(conn, sourceResponse);
Boolean noEntityBody = (Boolean) msgContext.getProperty(PassThroughConstants.NO_ENTITY_BODY);
Pipe pipe = (Pipe) msgContext.getProperty(PassThroughConstants.PASS_THROUGH_PIPE);
if ((noEntityBody == null || !noEntityBody) || pipe != null) {
if (pipe == null) {
pipe = new Pipe(sourceConfiguration.getBufferFactory().getBuffer(), "Test", sourceConfiguration);
msgContext.setProperty(PassThroughConstants.PASS_THROUGH_PIPE, pipe);
msgContext.setProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED, Boolean.TRUE);
}
pipe.attachConsumer(conn);
sourceResponse.connect(pipe);
}
Integer errorCode = (Integer) msgContext.getProperty(PassThroughConstants.ERROR_CODE);
if (errorCode != null) {
sourceResponse.setStatus(HttpStatus.SC_BAD_GATEWAY);
SourceContext.get(conn).setShutDown(true);
}
ProtocolState state = SourceContext.getState(conn);
if (state != null && state.compareTo(ProtocolState.REQUEST_DONE) <= 0) {
// start sending the response if we
boolean noEntityBodyResponse = false;
if (noEntityBody != null && Boolean.TRUE == noEntityBody && pipe != null) {
OutputStream out = pipe.getOutputStream();
out.write(new byte[0]);
pipe.setRawSerializationComplete(true);
out.close();
noEntityBodyResponse = true;
}
if (!noEntityBodyResponse && msgContext.isPropertyTrue(PassThroughConstants.MESSAGE_BUILDER_INVOKED) && pipe != null) {
OutputStream out = pipe.getOutputStream();
// when there is no SOAPAction.
if (Constants.VALUE_TRUE.equals(msgContext.getProperty(Constants.Configuration.ENABLE_MTOM)) || Constants.VALUE_TRUE.equals(msgContext.getProperty(Constants.Configuration.ENABLE_SWA))) {
msgContext.setProperty(Constants.Configuration.CONTENT_TYPE, PassThroughConstants.CONTENT_TYPE_MULTIPART_RELATED);
msgContext.setProperty(Constants.Configuration.MESSAGE_TYPE, PassThroughConstants.CONTENT_TYPE_MULTIPART_RELATED);
}
MessageFormatter formatter = MessageFormatterDecoratorFactory.createMessageFormatterDecorator(msgContext);
OMOutputFormat format = PassThroughTransportUtils.getOMOutputFormat(msgContext);
Object contentTypeInMsgCtx = msgContext.getProperty(org.apache.axis2.Constants.Configuration.CONTENT_TYPE);
boolean isContentTypeSetFromMsgCtx = false;
// If ContentType header is set in the axis2 message context, use it.
if (contentTypeInMsgCtx != null) {
String contentTypeValueInMsgCtx = contentTypeInMsgCtx.toString();
// Skip multipart/related as it should be taken from formatter.
if (!(contentTypeValueInMsgCtx.contains(PassThroughConstants.CONTENT_TYPE_MULTIPART_RELATED) || contentTypeValueInMsgCtx.contains(PassThroughConstants.CONTENT_TYPE_MULTIPART_FORM_DATA))) {
// adding charset only if charset is not available,
if (contentTypeValueInMsgCtx.indexOf(HTTPConstants.CHAR_SET_ENCODING) == -1 && format != null) {
String encoding = format.getCharSetEncoding();
if (encoding != null) {
sourceResponse.removeHeader(HTTP.CONTENT_TYPE);
contentTypeValueInMsgCtx += "; charset=" + encoding;
}
}
sourceResponse.addHeader(HTTP.CONTENT_TYPE, contentTypeValueInMsgCtx);
isContentTypeSetFromMsgCtx = true;
}
}
// If ContentType is not set from msg context, get the formatter ContentType
if (!isContentTypeSetFromMsgCtx) {
sourceResponse.removeHeader(HTTP.CONTENT_TYPE);
sourceResponse.addHeader(HTTP.CONTENT_TYPE, formatter.getContentType(msgContext, format, msgContext.getSoapAction()));
}
try {
formatter.writeTo(msgContext, format, out, false);
} catch (RemoteException fault) {
IOUtils.closeQuietly(out);
throw fault;
} finally {
// Serialization should be set as complete so that the state of the socket can be
// reset to readable
pipe.setSerializationComplete(true);
}
out.close();
}
conn.requestOutput();
} else {
// nothing much to do as we have started the response already
if (errorCode != null) {
if (log.isDebugEnabled()) {
log.warn("A Source connection is closed because of an " + "error in target: " + conn);
}
} else {
log.debug("A Source Connection is closed, because source handler " + "is already in the process of writing a response while " + "another response is submitted: " + conn);
}
pipe.consumerError();
SourceContext.updateState(conn, ProtocolState.CLOSED);
sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
}
}
use of org.apache.http.nio.NHttpServerConnection in project wso2-synapse by wso2.
the class ServerWorker method handleException.
private void handleException(String msg, Exception e) {
if (e == null) {
log.error(msg);
} else {
log.error(msg, e);
}
if (e == null) {
e = new Exception(msg);
}
try {
MessageContext faultContext = MessageContextBuilder.createFaultMessageContext(msgContext, e);
msgContext.setProperty(PassThroughConstants.FORCE_SOAP_FAULT, Boolean.TRUE);
AxisEngine.sendFault(faultContext);
} catch (Exception ex) {
NHttpServerConnection conn = request.getConnection();
SourceResponse sourceResponse;
msgContext.removeProperty(MessageContext.TRANSPORT_HEADERS);
if (log.isDebugEnabled()) {
log.debug("Sending ACK response with status " + msgContext.getProperty(NhttpConstants.HTTP_SC) + ", for MessageID : " + msgContext.getMessageID());
}
sourceResponse = SourceResponseFactory.create(msgContext, request, sourceConfiguration);
sourceResponse.addHeader(HTTP.CONTENT_TYPE, "text/html");
sourceResponse.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR);
Pipe pipe = new Pipe(sourceConfiguration.getBufferFactory().getBuffer(), "Test", sourceConfiguration);
msgContext.setProperty(PassThroughConstants.PASS_THROUGH_PIPE, pipe);
msgContext.setProperty(PassThroughConstants.MESSAGE_BUILDER_INVOKED, Boolean.TRUE);
pipe.attachConsumer(conn);
sourceResponse.connect(pipe);
OutputStream os = pipe.getOutputStream();
try {
String body = "<html><body><h1>" + "Failed to process the request" + "</h1><p>" + msg + "</p>";
if (e != null) {
body = body + "<p>" + e.getMessage() + "</p></body></html>";
}
if (ex != null) {
body = body + "<p>" + ex.getMessage() + "</p></body></html>";
}
os.write(body.getBytes());
os.flush();
os.close();
} catch (Exception ignore) {
}
pipe.setSerializationCompleteWithoutData(true);
SourceContext.setResponse(conn, sourceResponse);
ProtocolState state = SourceContext.getState(conn);
if (state != null && state.compareTo(ProtocolState.REQUEST_DONE) <= 0) {
conn.requestOutput();
} else {
SourceContext.updateState(conn, ProtocolState.CLOSED);
sourceConfiguration.getSourceConnections().shutDownConnection(conn, true);
}
}
}
use of org.apache.http.nio.NHttpServerConnection in project wso2-synapse by wso2.
the class ServerHandler method markActiveConnectionsToBeClosed.
public void markActiveConnectionsToBeClosed() {
log.info("Marking the closing signal on the connection pool of size : " + activeConnections.size());
synchronized (this) {
for (NHttpServerConnection conn : activeConnections) {
conn.getContext().setAttribute(NhttpConstants.FORCE_CLOSING, "true");
conn.requestOutput();
}
}
}
Aggregations