package de.hanbei.httpserver; import com.sun.net.httpserver.Headers; import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import de.hanbei.httpserver.common.Header; import de.hanbei.httpserver.common.Method; import de.hanbei.httpserver.exceptions.ServerErrorException; import de.hanbei.httpserver.request.Request; import de.hanbei.httpserver.response.Response; import org.apache.commons.io.IOUtils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.net.URI; import java.util.HashMap; import java.util.Map; import static java.lang.Math.max; class MockHttpHandler implements HttpHandler { private Map<Method, Mapping<Response>> predefinedResponses; private Map<Method, Mapping<RequestProcessor>> requestProcessorMapping; private Response defaultResponse; private boolean timeout; public MockHttpHandler() { requestProcessorMapping = new HashMap<Method, Mapping<RequestProcessor>>(); predefinedResponses = new HashMap<Method, Mapping<Response>>(); defaultResponse = Response.notFound().build(); } @Override public void handle(HttpExchange httpExchange) throws IOException { Method method = Method.valueOf(httpExchange.getRequestMethod()); URI requestURI = httpExchange.getRequestURI(); Response response = getResponse(requestURI, method); RequestProcessor processor = getProcessor(method, requestURI); if (processor != null) { try { Request request = portRequest(httpExchange); response = processor.process(request); } catch (Exception e) { throw new ServerErrorException("Error in porting requests", e); } } try { if (!timeout) { sendHeaders(httpExchange, response); sendContent(httpExchange, response); } } catch (Exception e) { throw new ServerErrorException("Error sending the response", e); } finally { httpExchange.close(); } } private Request portRequest(HttpExchange httpExchange) throws IOException { Request request = new Request(); Headers requestHeaders = httpExchange.getRequestHeaders(); Header header = request.getHeader(); for (String key : requestHeaders.keySet()) { for (String value : requestHeaders.get(key)) { header.addParameter(key, value); } } String encoding = requestHeaders.getFirst(Header.Fields.CONTENT_ENCODING); if (encoding != null) { request.getContent().setEncoding(encoding); } request.getContent().setLanguage(requestHeaders.getFirst(Header.Fields.CONTENT_LANGUAGE)); request.getContent().setMd5(requestHeaders.getFirst(Header.Fields.CONTENT_MD5)); String contentType = requestHeaders.getFirst(Header.Fields.CONTENT_TYPE); if (contentType != null) { if (encoding != null) { request.getContent().setMimetype(contentType + ";" + encoding); } else { request.getContent().setMimetype(contentType); } } String contentRange = requestHeaders.getFirst(Header.Fields.CONTENT_RANGE); if (contentRange != null) { request.getContent().setRange(contentRange); } ByteArrayOutputStream bytes = new ByteArrayOutputStream(); IOUtils.copy(httpExchange.getRequestBody(), bytes); request.getContent().setContent(bytes.toByteArray()); return request; } private void sendContent(HttpExchange httpExchange, Response defaultResponse) throws IOException { httpExchange.getResponseBody().write(defaultResponse.getContent().getContent()); } private void sendHeaders(HttpExchange httpExchange, Response response) throws IOException { int length = response.getContent().getLength(); int statusCode = response.getStatus().getStatusCode(); Headers responseHeaders = httpExchange.getResponseHeaders(); Header headers = response.getHeader(); for (String headerField : headers.getHeaderFields()) { for (Header.Parameter value : headers.getHeaderParameter(headerField)) { responseHeaders.add(headerField, value.toString()); } } addHeaderIfSet(responseHeaders, Header.Fields.CONTENT_ENCODING, response.getContent().getEncoding()); addHeaderIfSet(responseHeaders, Header.Fields.CONTENT_LANGUAGE, response.getContent().getLanguage()); addHeaderIfSet(responseHeaders, Header.Fields.CONTENT_MD5, response.getContent().getMd5()); addHeaderIfSet(responseHeaders, Header.Fields.CONTENT_TYPE, response.getContent().getComposedContentType()); addHeaderIfSet(responseHeaders, Header.Fields.CONTENT_RANGE, response.getContent().getRange()); httpExchange.sendResponseHeaders(statusCode, max(0, length)); } private void addHeaderIfSet(Headers responseHeaders, String name, String value) { if(value != null) { responseHeaders.add(name, value); } } private Response getResponse(URI requestUri1, Method method) { String requestUri = trimSlashes(requestUri1); Mapping<Response> mapping = predefinedResponses.get(method); if (mapping == null) { return defaultResponse; } Response response = mapping.get(requestUri); if (response == null) { return defaultResponse; } return response; } public Response getDefaultResponse() { return defaultResponse; } public void setDefaultResponse(Response defaultResponse) { this.defaultResponse = defaultResponse; } /** * Add a specified response for a certain url and method. The uri has to be relative to the server url. * * @param method The method the response should be sent on. * @param uri The uri the request will access on. Has to be relative to the server url. * @param response The response that should be sent on a request on the specified uri with the specified method. */ public void addResponse(Method method, URI uri, Response response) { Mapping<Response> mapping = predefinedResponses.get(method); if (mapping == null) { mapping = new Mapping<Response>(); predefinedResponses.put(method, mapping); } mapping.add(trimSlashes(uri), response); } private RequestProcessor getProcessor(Method method, URI requestUriP) { String requestUri = trimSlashes(requestUriP); Mapping<RequestProcessor> mapping = requestProcessorMapping.get(method); RequestProcessor processor = null; if (mapping != null) { processor = mapping.get(requestUri); } return processor; } private String trimSlashes(URI uri) { String uriString = uri.toString(); return uriString.replaceAll("^/|/$", ""); } /** * Set if the server should timeout on requests. * * @param shouldTimeout true if the server should timeout, false otherwise. */ public void setTimeout(boolean shouldTimeout) { timeout = shouldTimeout; } /** * Is the server set to timeout on requests. * * @return True if the server is set to timeout. */ public boolean isTimeoutSet() { return timeout; } /** * Add a {@link de.hanbei.httpserver.RequestProcessor} for a certain url and a method. It should make sense only POST and PUT requests as these are the only * ones that have a request body. * * @param method The method the response should be sent on. * @param uri The uri the request will access on. Has to be relative to the server url. * @param processor The {@link RequestProcessor} that processes the request body. */ public void addRequestProcessor(Method method, URI uri, RequestProcessor processor) { Mapping<RequestProcessor> mapping = requestProcessorMapping.get(method); if (mapping == null) { mapping = new Mapping<RequestProcessor>(); requestProcessorMapping.put(method, mapping); } mapping.add(trimSlashes(uri), processor); } }