001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.remoting.httpinvoker; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.io.ObjectInputStream; 022import java.io.ObjectOutputStream; 023import java.io.OutputStream; 024 025import com.sun.net.httpserver.HttpExchange; 026import com.sun.net.httpserver.HttpHandler; 027 028import org.springframework.remoting.rmi.RemoteInvocationSerializingExporter; 029import org.springframework.remoting.support.RemoteInvocation; 030import org.springframework.remoting.support.RemoteInvocationResult; 031 032/** 033 * HTTP request handler that exports the specified service bean as 034 * HTTP invoker service endpoint, accessible via an HTTP invoker proxy. 035 * Designed for Sun's JRE 1.6 HTTP server, implementing the 036 * {@link com.sun.net.httpserver.HttpHandler} interface. 037 * 038 * <p>Deserializes remote invocation objects and serializes remote invocation 039 * result objects. Uses Java serialization just like RMI, but provides the 040 * same ease of setup as Caucho's HTTP-based Hessian protocol. 041 * 042 * <p><b>HTTP invoker is the recommended protocol for Java-to-Java remoting.</b> 043 * It is more powerful and more extensible than Hessian, at the expense of 044 * being tied to Java. Nevertheless, it is as easy to set up as Hessian, 045 * which is its main advantage compared to RMI. 046 * 047 * <p><b>WARNING: Be aware of vulnerabilities due to unsafe Java deserialization: 048 * Manipulated input streams could lead to unwanted code execution on the server 049 * during the deserialization step. As a consequence, do not expose HTTP invoker 050 * endpoints to untrusted clients but rather just between your own services.</b> 051 * In general, we strongly recommend any other message format (e.g. JSON) instead. 052 * 053 * @author Juergen Hoeller 054 * @since 2.5.1 055 * @see org.springframework.remoting.httpinvoker.HttpInvokerClientInterceptor 056 * @see org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean 057 * @deprecated as of Spring Framework 5.1, in favor of {@link HttpInvokerServiceExporter} 058 */ 059@Deprecated 060@org.springframework.lang.UsesSunHttpServer 061public class SimpleHttpInvokerServiceExporter extends RemoteInvocationSerializingExporter implements HttpHandler { 062 063 /** 064 * Reads a remote invocation from the request, executes it, 065 * and writes the remote invocation result to the response. 066 * @see #readRemoteInvocation(HttpExchange) 067 * @see #invokeAndCreateResult(RemoteInvocation, Object) 068 * @see #writeRemoteInvocationResult(HttpExchange, RemoteInvocationResult) 069 */ 070 @Override 071 public void handle(HttpExchange exchange) throws IOException { 072 try { 073 RemoteInvocation invocation = readRemoteInvocation(exchange); 074 RemoteInvocationResult result = invokeAndCreateResult(invocation, getProxy()); 075 writeRemoteInvocationResult(exchange, result); 076 exchange.close(); 077 } 078 catch (ClassNotFoundException ex) { 079 exchange.sendResponseHeaders(500, -1); 080 logger.error("Class not found during deserialization", ex); 081 } 082 } 083 084 /** 085 * Read a RemoteInvocation from the given HTTP request. 086 * <p>Delegates to {@link #readRemoteInvocation(HttpExchange, InputStream)} 087 * with the {@link HttpExchange#getRequestBody()} request's input stream}. 088 * @param exchange current HTTP request/response 089 * @return the RemoteInvocation object 090 * @throws java.io.IOException in case of I/O failure 091 * @throws ClassNotFoundException if thrown by deserialization 092 */ 093 protected RemoteInvocation readRemoteInvocation(HttpExchange exchange) 094 throws IOException, ClassNotFoundException { 095 096 return readRemoteInvocation(exchange, exchange.getRequestBody()); 097 } 098 099 /** 100 * Deserialize a RemoteInvocation object from the given InputStream. 101 * <p>Gives {@link #decorateInputStream} a chance to decorate the stream 102 * first (for example, for custom encryption or compression). Creates a 103 * {@link org.springframework.remoting.rmi.CodebaseAwareObjectInputStream} 104 * and calls {@link #doReadRemoteInvocation} to actually read the object. 105 * <p>Can be overridden for custom serialization of the invocation. 106 * @param exchange current HTTP request/response 107 * @param is the InputStream to read from 108 * @return the RemoteInvocation object 109 * @throws java.io.IOException in case of I/O failure 110 * @throws ClassNotFoundException if thrown during deserialization 111 */ 112 protected RemoteInvocation readRemoteInvocation(HttpExchange exchange, InputStream is) 113 throws IOException, ClassNotFoundException { 114 115 ObjectInputStream ois = createObjectInputStream(decorateInputStream(exchange, is)); 116 return doReadRemoteInvocation(ois); 117 } 118 119 /** 120 * Return the InputStream to use for reading remote invocations, 121 * potentially decorating the given original InputStream. 122 * <p>The default implementation returns the given stream as-is. 123 * Can be overridden, for example, for custom encryption or compression. 124 * @param exchange current HTTP request/response 125 * @param is the original InputStream 126 * @return the potentially decorated InputStream 127 * @throws java.io.IOException in case of I/O failure 128 */ 129 protected InputStream decorateInputStream(HttpExchange exchange, InputStream is) throws IOException { 130 return is; 131 } 132 133 /** 134 * Write the given RemoteInvocationResult to the given HTTP response. 135 * @param exchange current HTTP request/response 136 * @param result the RemoteInvocationResult object 137 * @throws java.io.IOException in case of I/O failure 138 */ 139 protected void writeRemoteInvocationResult(HttpExchange exchange, RemoteInvocationResult result) 140 throws IOException { 141 142 exchange.getResponseHeaders().set("Content-Type", getContentType()); 143 exchange.sendResponseHeaders(200, 0); 144 writeRemoteInvocationResult(exchange, result, exchange.getResponseBody()); 145 } 146 147 /** 148 * Serialize the given RemoteInvocation to the given OutputStream. 149 * <p>The default implementation gives {@link #decorateOutputStream} a chance 150 * to decorate the stream first (for example, for custom encryption or compression). 151 * Creates an {@link java.io.ObjectOutputStream} for the final stream and calls 152 * {@link #doWriteRemoteInvocationResult} to actually write the object. 153 * <p>Can be overridden for custom serialization of the invocation. 154 * @param exchange current HTTP request/response 155 * @param result the RemoteInvocationResult object 156 * @param os the OutputStream to write to 157 * @throws java.io.IOException in case of I/O failure 158 * @see #decorateOutputStream 159 * @see #doWriteRemoteInvocationResult 160 */ 161 protected void writeRemoteInvocationResult( 162 HttpExchange exchange, RemoteInvocationResult result, OutputStream os) throws IOException { 163 164 ObjectOutputStream oos = createObjectOutputStream(decorateOutputStream(exchange, os)); 165 doWriteRemoteInvocationResult(result, oos); 166 oos.flush(); 167 } 168 169 /** 170 * Return the OutputStream to use for writing remote invocation results, 171 * potentially decorating the given original OutputStream. 172 * <p>The default implementation returns the given stream as-is. 173 * Can be overridden, for example, for custom encryption or compression. 174 * @param exchange current HTTP request/response 175 * @param os the original OutputStream 176 * @return the potentially decorated OutputStream 177 * @throws java.io.IOException in case of I/O failure 178 */ 179 protected OutputStream decorateOutputStream(HttpExchange exchange, OutputStream os) throws IOException { 180 return os; 181 } 182 183}