Browse Source
This commit adds RxNetty integration that includes RxNetty-based implementations of ServerHttpRequest and ServerHttpResponse as well as an adapter from the RxNetty RequestHandler to the HttpHandler contracts. Only byte[] is supported at the moment for reading and writing with a corresponding copy to and from Netty ByteBuf.pull/1111/head
5 changed files with 258 additions and 0 deletions
@ -0,0 +1,50 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2015 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.reactive.web.rxnetty; |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.reactivex.netty.protocol.http.server.HttpServerRequest; |
||||||
|
import io.reactivex.netty.protocol.http.server.HttpServerResponse; |
||||||
|
import io.reactivex.netty.protocol.http.server.RequestHandler; |
||||||
|
import org.reactivestreams.Publisher; |
||||||
|
import rx.Observable; |
||||||
|
import rx.RxReactiveStreams; |
||||||
|
|
||||||
|
import org.springframework.reactive.web.HttpHandler; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class RequestHandlerAdapter implements RequestHandler<ByteBuf, ByteBuf> { |
||||||
|
|
||||||
|
private final HttpHandler httpHandler; |
||||||
|
|
||||||
|
|
||||||
|
public RequestHandlerAdapter(HttpHandler httpHandler) { |
||||||
|
Assert.notNull(httpHandler, "'httpHandler' is required."); |
||||||
|
this.httpHandler = httpHandler; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Observable<Void> handle(HttpServerRequest<ByteBuf> request, HttpServerResponse<ByteBuf> response) { |
||||||
|
RxNettyServerHttpRequest adaptedRequest = new RxNettyServerHttpRequest(request); |
||||||
|
RxNettyServerHttpResponse adaptedResponse = new RxNettyServerHttpResponse(response); |
||||||
|
Publisher<Void> result = this.httpHandler.handle(adaptedRequest, adaptedResponse); |
||||||
|
return RxReactiveStreams.toObservable(result); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,86 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2015 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.reactive.web.rxnetty; |
||||||
|
|
||||||
|
import java.net.URI; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.reactivex.netty.protocol.http.server.HttpServerRequest; |
||||||
|
import org.reactivestreams.Publisher; |
||||||
|
import rx.Observable; |
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.HttpMethod; |
||||||
|
import org.springframework.reactive.web.ServerHttpRequest; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class RxNettyServerHttpRequest implements ServerHttpRequest { |
||||||
|
|
||||||
|
private final HttpServerRequest<ByteBuf> request; |
||||||
|
|
||||||
|
private HttpHeaders headers; |
||||||
|
|
||||||
|
|
||||||
|
public RxNettyServerHttpRequest(HttpServerRequest<ByteBuf> request) { |
||||||
|
Assert.notNull("'request', request must not be null."); |
||||||
|
this.request = request; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public HttpHeaders getHeaders() { |
||||||
|
if (this.headers == null) { |
||||||
|
this.headers = new HttpHeaders(); |
||||||
|
for (String name : this.request.getHeaderNames()) { |
||||||
|
for (String value : this.request.getAllHeaderValues(name)) { |
||||||
|
this.headers.add(name, value); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return this.headers; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public HttpMethod getMethod() { |
||||||
|
return HttpMethod.valueOf(this.request.getHttpMethod().name()); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public URI getURI() { |
||||||
|
try { |
||||||
|
return new URI(this.request.getUri()); |
||||||
|
} |
||||||
|
catch (URISyntaxException ex) { |
||||||
|
throw new IllegalStateException("Could not get URI: " + ex.getMessage(), ex); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Publisher<byte[]> getBody() { |
||||||
|
Observable<byte[]> bytesContent = this.request.getContent().map(byteBuf -> { |
||||||
|
byte[] copy = new byte[byteBuf.readableBytes()]; |
||||||
|
byteBuf.readBytes(copy); |
||||||
|
return copy; |
||||||
|
}); |
||||||
|
return rx.RxReactiveStreams.toPublisher(bytesContent); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
@ -0,0 +1,72 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2015 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.reactive.web.rxnetty; |
||||||
|
|
||||||
|
import io.netty.handler.codec.http.HttpResponseStatus; |
||||||
|
import io.reactivex.netty.protocol.http.server.HttpServerResponse; |
||||||
|
import org.reactivestreams.Publisher; |
||||||
|
import rx.Observable; |
||||||
|
import rx.RxReactiveStreams; |
||||||
|
|
||||||
|
import org.springframework.http.HttpHeaders; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.reactive.web.ServerHttpResponse; |
||||||
|
import org.springframework.util.Assert; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class RxNettyServerHttpResponse implements ServerHttpResponse { |
||||||
|
|
||||||
|
private final HttpServerResponse<?> response; |
||||||
|
|
||||||
|
private final HttpHeaders headers; |
||||||
|
|
||||||
|
private boolean headersWritten = false; |
||||||
|
|
||||||
|
|
||||||
|
public RxNettyServerHttpResponse(HttpServerResponse<?> response) { |
||||||
|
Assert.notNull("'response', response must not be null."); |
||||||
|
this.response = response; |
||||||
|
this.headers = new HttpHeaders(); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
@Override |
||||||
|
public void setStatusCode(HttpStatus status) { |
||||||
|
this.response.setStatus(HttpResponseStatus.valueOf(status.value())); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public HttpHeaders getHeaders() { |
||||||
|
return (this.headersWritten ? HttpHeaders.readOnlyHttpHeaders(this.headers) : this.headers); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Publisher<Void> writeWith(Publisher<byte[]> contentPublisher) { |
||||||
|
writeHeaders(); |
||||||
|
Observable<byte[]> contentObservable = RxReactiveStreams.toObservable(contentPublisher); |
||||||
|
return RxReactiveStreams.toPublisher(this.response.writeBytes(contentObservable)); |
||||||
|
} |
||||||
|
|
||||||
|
private void writeHeaders() { |
||||||
|
if (!this.headersWritten) { |
||||||
|
for (String name : this.headers.keySet()) { |
||||||
|
this.response.setHeader(name, this.headers.get(name)); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2002-2015 the original author or authors. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
package org.springframework.reactive.web.rxnetty; |
||||||
|
|
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.reactivex.netty.protocol.http.server.HttpServer; |
||||||
|
import org.junit.AfterClass; |
||||||
|
import org.junit.BeforeClass; |
||||||
|
|
||||||
|
import org.springframework.reactive.web.EchoHandler; |
||||||
|
import org.springframework.reactive.web.AbstractHttpHandlerIntegrationTestCase; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Rossen Stoyanchev |
||||||
|
*/ |
||||||
|
public class HttpHandlerRxNettyIntegrationTests extends AbstractHttpHandlerIntegrationTestCase { |
||||||
|
|
||||||
|
private static HttpServer<ByteBuf, ByteBuf> httpServer; |
||||||
|
|
||||||
|
|
||||||
|
@BeforeClass |
||||||
|
public static void startServer() throws Exception { |
||||||
|
RequestHandlerAdapter requestHandler = new RequestHandlerAdapter(new EchoHandler()); |
||||||
|
httpServer = HttpServer.newServer(port); |
||||||
|
httpServer.start(requestHandler::handle); |
||||||
|
} |
||||||
|
|
||||||
|
@AfterClass |
||||||
|
public static void stopServer() throws Exception { |
||||||
|
httpServer.shutdown(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
Loading…
Reference in new issue