/**
* Copyright 2005-2014 Restlet
*
* The contents of this file are subject to the terms of one of the following
* open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can
* select the license that you prefer but you may not use this file except in
* compliance with one of these Licenses.
*
* You can obtain a copy of the Apache 2.0 license at
* http://www.opensource.org/licenses/apache-2.0
*
* You can obtain a copy of the EPL 1.0 license at
* http://www.opensource.org/licenses/eclipse-1.0
*
* See the Licenses for the specific language governing permissions and
* limitations under the Licenses.
*
* Alternatively, you can obtain a royalty free commercial license with less
* limitations, transferable or non-transferable, directly at
* http://restlet.com/products/restlet-framework
*
* Restlet is a registered trademark of Restlet S.A.S.
*/
package org.restlet.engine.adapter;
import java.io.IOException;
import java.security.cert.Certificate;
import java.util.List;
import java.util.logging.Level;
import org.restlet.Context;
import org.restlet.data.Header;
import org.restlet.data.Method;
import org.restlet.data.Status;
import org.restlet.engine.header.HeaderConstants;
import org.restlet.engine.header.HeaderUtils;
import org.restlet.representation.Representation;
import org.restlet.util.Series;
// [excludes gwt]
/**
* Converter of low-level HTTP server calls into high-level uniform calls.
*
* @author Jerome Louvel
*/
public class ServerAdapter extends Adapter {
/**
* Constructor.
*
* @param context
* The client context.
*/
public ServerAdapter(Context context) {
super(context);
}
/**
* Adds the entity headers for the handled uniform call.
*
* @param response
* The response returned.
*/
protected void addEntityHeaders(HttpResponse response) {
Series<Header> responseHeaders = response.getHttpCall()
.getResponseHeaders();
Representation entity = response.getEntity();
HeaderUtils.addEntityHeaders(entity, responseHeaders);
}
/**
* Adds the response headers for the handled uniform call.
*
* @param response
* The response returned.
*/
protected void addResponseHeaders(HttpResponse response) {
try {
// Add all the necessary headers
HeaderUtils.addGeneralHeaders(response, response.getHttpCall()
.getResponseHeaders());
HeaderUtils.addResponseHeaders(response, response.getHttpCall()
.getResponseHeaders());
// Set the status code in the response
if (response.getStatus() != null) {
response.getHttpCall().setStatusCode(
response.getStatus().getCode());
response.getHttpCall().setReasonPhrase(
response.getStatus().getReasonPhrase());
}
} catch (Exception e) {
getLogger().log(Level.WARNING,
"Exception intercepted while adding the response headers",
e);
response.getHttpCall().setStatusCode(
Status.SERVER_ERROR_INTERNAL.getCode());
response.getHttpCall().setReasonPhrase(
Status.SERVER_ERROR_INTERNAL.getReasonPhrase());
}
}
/**
* Commits the changes to a handled uniform call back into the original HTTP
* call. The default implementation first invokes the "addResponseHeaders"
* then asks the "htppCall" to send the response back to the client.
*
* @param response
* The high-level response.
*/
public void commit(HttpResponse response) {
try {
if ((response.getRequest().getMethod() != null)
&& response.getRequest().getMethod().equals(Method.HEAD)) {
addEntityHeaders(response);
response.setEntity(null);
} else if (Method.GET.equals(response.getRequest().getMethod())
&& Status.SUCCESS_OK.equals(response.getStatus())
&& (!response.isEntityAvailable())) {
addEntityHeaders(response);
getLogger()
.warning(
"A response with a 200 (Ok) status should have an entity. Make sure that resource \""
+ response.getRequest()
.getResourceRef()
+ "\" returns one or sets the status to 204 (No content).");
} else if (response.getStatus().equals(Status.SUCCESS_NO_CONTENT)) {
addEntityHeaders(response);
if (response.isEntityAvailable()) {
getLogger()
.fine("Responses with a 204 (No content) status generally don't have an entity. Only adding entity headers for resource \""
+ response.getRequest().getResourceRef()
+ "\".");
response.setEntity(null);
}
} else if (response.getStatus()
.equals(Status.SUCCESS_RESET_CONTENT)) {
if (response.isEntityAvailable()) {
getLogger()
.warning(
"Responses with a 205 (Reset content) status can't have an entity. Ignoring the entity for resource \""
+ response.getRequest()
.getResourceRef() + "\".");
response.setEntity(null);
}
} else if (response.getStatus().equals(
Status.REDIRECTION_NOT_MODIFIED)) {
if (response.getEntity() != null) {
HeaderUtils.addNotModifiedEntityHeaders(response
.getEntity(), response.getHttpCall()
.getResponseHeaders());
response.setEntity(null);
}
} else if (response.getStatus().isInformational()) {
if (response.isEntityAvailable()) {
getLogger()
.warning(
"Responses with an informational (1xx) status can't have an entity. Ignoring the entity for resource \""
+ response.getRequest()
.getResourceRef() + "\".");
response.setEntity(null);
}
} else {
addEntityHeaders(response);
if (!response.isEntityAvailable()) {
if ((response.getEntity() != null)
&& (response.getEntity().getSize() != 0)) {
getLogger()
.warning(
"A response with an unavailable and potentially non empty entity was returned. Ignoring the entity for resource \""
+ response.getRequest()
.getResourceRef()
+ "\".");
}
response.setEntity(null);
}
}
// Add the response headers
addResponseHeaders(response);
// Send the response to the client
response.getHttpCall().sendResponse(response);
} catch (Throwable t) {
// [ifndef gae]
if (response.getHttpCall().isConnectionBroken(t)) {
// output a single log line for this common case to avoid filling servers logs
getLogger().log(Level.INFO, "The connection was broken. It was probably closed by the client. Reason: " + t.getMessage());
} else
// [enddef]
{
getLogger().log(Level.SEVERE,
"An exception occurred writing the response entity", t);
response.getHttpCall().setStatusCode(
Status.SERVER_ERROR_INTERNAL.getCode());
response.getHttpCall().setReasonPhrase(
"An exception occurred writing the response entity");
response.setEntity(null);
try {
response.getHttpCall().sendResponse(response);
} catch (IOException ioe) {
getLogger().log(Level.WARNING,
"Unable to send error response", ioe);
}
}
} finally {
response.getHttpCall().complete();
if (response.getOnSent() != null) {
response.getOnSent().handle(response.getRequest(), response);
}
}
}
/**
* Converts a low-level HTTP call into a high-level uniform request.
*
* @param httpCall
* The low-level HTTP call.
* @return A new high-level uniform request.
*/
public HttpRequest toRequest(ServerCall httpCall) {
HttpRequest result = new HttpRequest(getContext(), httpCall);
result.getAttributes().put(HeaderConstants.ATTRIBUTE_HEADERS,
httpCall.getRequestHeaders());
if (httpCall.getVersion() != null) {
result.getAttributes().put(HeaderConstants.ATTRIBUTE_VERSION,
httpCall.getVersion());
}
if (httpCall.isConfidential()) {
List<Certificate> clientCertificates = httpCall.getCertificates();
if (clientCertificates != null) {
result.getClientInfo().setCertificates(clientCertificates);
}
String cipherSuite = httpCall.getCipherSuite();
if (cipherSuite != null) {
result.getClientInfo().setCipherSuite(cipherSuite);
}
Integer keySize = httpCall.getSslKeySize();
if (keySize != null) {
result.getAttributes().put(
HeaderConstants.ATTRIBUTE_HTTPS_KEY_SIZE, keySize);
}
String sslSessionId = httpCall.getSslSessionId();
if (sslSessionId != null) {
result.getAttributes().put(
HeaderConstants.ATTRIBUTE_HTTPS_SSL_SESSION_ID,
sslSessionId);
}
}
return result;
}
}