in modules/transports/core/nhttp/src/main/java/org/apache/synapse/transport/nhttp/ServerWorker.java [212:391]
public void run() {
String method = request.getRequestLine().getMethod().toUpperCase();
msgContext.setProperty(Constants.Configuration.HTTP_METHOD,
request.getRequestLine().getMethod());
if (NHttpConfiguration.getInstance().isHttpMethodDisabled(method)) {
handleException("Unsupported method : " + method, null);
}
String uri = request.getRequestLine().getUri();
String oriUri = uri;
if (uri.indexOf(cfgCtx.getServicePath()) != -1) {
// discard upto servicePath
uri = uri.substring(uri.indexOf(cfgCtx.getServicePath()) +
cfgCtx.getServicePath().length());
// discard [proxy] service name if any
int pos = uri.indexOf("/", 1);
if (pos > 0) {
uri = uri.substring(pos);
} else {
pos = uri.indexOf("?");
if (pos != -1) {
uri = uri.substring(pos);
} else {
uri = "";
}
}
} else {
// remove any absolute prefix if any
int pos = uri.indexOf("://");
if (pos != -1) {
uri = uri.substring(pos + 3);
}
pos = uri.indexOf("/");
if (pos != -1) {
uri = uri.substring(pos + 1);
}
}
msgContext.setProperty(NhttpConstants.REST_URL_POSTFIX, uri);
String servicePrefix = oriUri.substring(0, oriUri.indexOf(uri));
if (servicePrefix.indexOf("://") == -1) {
// If the URL in the request line is not absolute, then we first try to get the Host
// header to build the absolute URL. We only use the local network address/port of
// the HTTP connection if no Host header is present. This is not only consistent, but
// also avoids the overhead of the InetAddress#getHostName() method.
String host;
Header hostHeader = request.getFirstHeader(HTTP.TARGET_HOST);
if (hostHeader != null) {
host = hostHeader.getValue();
} else {
HttpInetConnection inetConn = (HttpInetConnection) conn;
InetAddress localAddr = inetConn.getLocalAddress();
if (localAddr != null) {
host = localAddr.getHostName() + ":" + inetConn.getLocalPort();
} else {
host = null;
}
}
if (host != null) {
servicePrefix = (isHttps ? "https://" : "http://") + host + servicePrefix;
}
}
msgContext.setProperty(NhttpConstants.SERVICE_PREFIX, servicePrefix);
if ("GET".equals(method)) {
httpGetRequestProcessor.process(request, response,
msgContext, conn, os, isRestDispatching);
} else if ("POST".equals(method)) {
processEntityEnclosingMethod();
} else if ("PUT".equals(method)) {
processEntityEnclosingMethod();
} else if ("HEAD".equals(method)) {
processNonEntityEnclosingMethod();
} else if ("OPTIONS".equals(method)) {
processNonEntityEnclosingMethod();
} else if ("DELETE".equals(method)) {
processGetAndDelete("DELETE");
} else if ("TRACE".equals(method)) {
processNonEntityEnclosingMethod();
} else {
handleException("Unsupported method : " + method, null);
}
// here the RequestResponseTransport plays an important role when it comes to
// dual channel invocation. This is becasue we need to ACK to the request once the request
// is received to synapse. Otherwise we will not be able to support the single channel
// invocation within the actual service and synapse for a dual channel request from the
// client.
if (isAckRequired()) {
String respWritten = "";
if (msgContext.getOperationContext() != null) {
respWritten = (String) msgContext.getOperationContext().getProperty(
Constants.RESPONSE_WRITTEN);
}
boolean respWillFollow = !Constants.VALUE_TRUE.equals(respWritten)
&& !"SKIP".equals(respWritten);
boolean acked = (((RequestResponseTransport) msgContext.getProperty(
RequestResponseTransport.TRANSPORT_CONTROL)).getStatus()
== RequestResponseTransport.RequestResponseTransportStatus.ACKED);
boolean forced = msgContext.isPropertyTrue(NhttpConstants.FORCE_SC_ACCEPTED);
boolean nioAck = msgContext.isPropertyTrue("NIO-ACK-Requested", false);
if (respWillFollow || acked || forced || nioAck) {
if (!nioAck) {
if (log.isDebugEnabled()) {
log.debug("Sending 202 Accepted response for MessageID : " +
msgContext.getMessageID() +
" response written : " + respWritten +
" response will follow : " + respWillFollow +
" acked : " + acked + " forced ack : " + forced);
}
response.setStatusCode(HttpStatus.SC_ACCEPTED);
} else {
if (log.isDebugEnabled()) {
log.debug("Sending ACK response with status "
+ msgContext.getProperty(NhttpConstants.HTTP_SC)
+ ", for MessageID : " + msgContext.getMessageID());
}
response.setStatusCode(Integer.parseInt(
msgContext.getProperty(NhttpConstants.HTTP_SC).toString()));
Map<String, String> responseHeaders = (Map<String, String>)
msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
if (responseHeaders != null) {
for (Map.Entry<String,String> entry : responseHeaders.entrySet()) {
response.addHeader(entry.getKey(), entry.getValue());
}
}
}
if (metrics != null) {
metrics.incrementMessagesSent();
}
try {
serverHandler.commitResponse(conn, response);
} catch (HttpException e) {
if (metrics != null) {
metrics.incrementFaultsSending();
}
handleException("Unexpected HTTP protocol error : " + e.getMessage(), e);
} catch (ConnectionClosedException e) {
if (metrics != null) {
metrics.incrementFaultsSending();
}
log.warn("Connection closed by client (Connection closed)");
} catch (IllegalStateException e) {
if (metrics != null) {
metrics.incrementFaultsSending();
}
log.warn("Connection closed by client (Buffer closed)");
} catch (IOException e) {
if (metrics != null) {
metrics.incrementFaultsSending();
}
handleException("IO Error sending response message", e);
} catch (Exception e) {
if (metrics != null) {
metrics.incrementFaultsSending();
}
handleException("General Error sending response message", e);
}
if (is != null) {
try {
is.close();
} catch (IOException ignore) {}
}
// make sure that the output stream is flushed and closed properly
try {
os.flush();
os.close();
} catch (IOException ignore) {}
}
}
}