diff --git a/docs/index.asciidoc b/docs/index.asciidoc index 30e8dd04..565934ca 100644 --- a/docs/index.asciidoc +++ b/docs/index.asciidoc @@ -197,6 +197,17 @@ invalid credentials (401), internal errors (503) or backpressure (429). If 204 (No Content) is set, the response body will not be sent in the response. +[id="plugins-{type}s-{plugin}-response_body"] +===== `response_body` + + * Value type is: <> + * Default value is `ok` + +The response body if the request is processed successfully. + +The response body is not validated and the `Content-type` is not adjusted to match its actual type. +No body will be sent if `response_code` is configured to 204 (No Content). + [id="plugins-{type}s-{plugin}-response_headers"] ===== `response_headers` diff --git a/lib/logstash/inputs/http.rb b/lib/logstash/inputs/http.rb index 323d8828..eb5c58a8 100644 --- a/lib/logstash/inputs/http.rb +++ b/lib/logstash/inputs/http.rb @@ -116,6 +116,8 @@ class LogStash::Inputs::Http < LogStash::Inputs::Base config :max_content_length, :validate => :number, :required => false, :default => 100 * 1024 * 1024 config :response_code, :validate => [200, 201, 202, 204], :default => 200 + + config :response_body, :validate => :string, :default => "ok" # Deprecated options # The JKS keystore to validate the client's certificates @@ -211,7 +213,7 @@ def validate_ssl_settings! def create_http_server(message_handler) org.logstash.plugins.inputs.http.NettyHttpServer.new( - @host, @port, message_handler, build_ssl_params(), @threads, @max_pending_requests, @max_content_length, @response_code) + @host, @port, message_handler, build_ssl_params(), @threads, @max_pending_requests, @max_content_length, @response_code, @response_body) end def build_ssl_params diff --git a/spec/inputs/http_spec.rb b/spec/inputs/http_spec.rb index c72b3c17..74e70b79 100644 --- a/spec/inputs/http_spec.rb +++ b/spec/inputs/http_spec.rb @@ -356,6 +356,55 @@ expect(response.code).to eq(202) end end + context "when response_code is set to 204" do + let(:code) { 204 } + subject { LogStash::Inputs::Http.new("port" => port, "response_code" => code) } + it "responds with the configured code and no body even if forced" do + response = client.post("http://127.0.0.1:#{port}", :body => "hello") + response.call + expect(response.code).to eq(204) + expect(response.body).to eq(nil) + end + end + end + describe "return body" do + context "when response_body is not configured" do + subject { LogStash::Inputs::Http.new("port" => port) } + it "responds with the default body" do + response = client.post("http://127.0.0.1:#{port}", :body => "hello") + response.call + expect(response.body).to eq("ok") + end + end + context "when response_body is configured" do + let(:body) { "world!" } + subject { LogStash::Inputs::Http.new("port" => port, "response_body" => body) } + it "responds with the configured body" do + response = client.post("http://127.0.0.1:#{port}", :body => "hello") + response.call + expect(response.body).to eq(body) + end + end + context "when response_body is configured to an empty string" do + let(:body) { "" } + subject { LogStash::Inputs::Http.new("port" => port, "response_body" => body) } + it "responds with the configured body" do + response = client.post("http://127.0.0.1:#{port}", :body => "hello") + response.call + expect(response.body).to eq(body) + end + end + context "when response_body is configured and content-type is specified" do + let(:body) { "{\"test\": \"body\"}" } + let(:custom_headers) { { 'content-type' => "application/json" } } + subject { LogStash::Inputs::Http.new("port" => port, "response_body" => body, "response_headers" => custom_headers) } + it "responds with the configured body and headers" do + response = client.post("http://127.0.0.1:#{port}", :body => "Plain-text") + response.call + expect(response.body).to eq(body) + expect(response.headers.to_hash).to include({ "content-type" => "application/json" }) + end + end end end diff --git a/src/main/java/org/logstash/plugins/inputs/http/HttpInitializer.java b/src/main/java/org/logstash/plugins/inputs/http/HttpInitializer.java index 27f21500..f02a7b28 100644 --- a/src/main/java/org/logstash/plugins/inputs/http/HttpInitializer.java +++ b/src/main/java/org/logstash/plugins/inputs/http/HttpInitializer.java @@ -21,13 +21,16 @@ public class HttpInitializer extends ChannelInitializer { private final int maxContentLength; private final HttpResponseStatus responseStatus; private final ThreadPoolExecutor executorGroup; + private final String responseBody; public HttpInitializer(IMessageHandler messageHandler, ThreadPoolExecutor executorGroup, - int maxContentLength, HttpResponseStatus responseStatus) { + int maxContentLength, HttpResponseStatus responseStatus, + String responseBody) { this.messageHandler = messageHandler; this.executorGroup = executorGroup; this.maxContentLength = maxContentLength; this.responseStatus = responseStatus; + this.responseBody = responseBody; } protected void initChannel(SocketChannel socketChannel) throws Exception { @@ -40,7 +43,7 @@ protected void initChannel(SocketChannel socketChannel) throws Exception { pipeline.addLast(new HttpServerCodec()); pipeline.addLast(new HttpContentDecompressor()); pipeline.addLast(new HttpObjectAggregator(maxContentLength)); - pipeline.addLast(new HttpServerHandler(messageHandler.copy(), executorGroup, responseStatus)); + pipeline.addLast(new HttpServerHandler(messageHandler.copy(), executorGroup, responseStatus, responseBody)); } public void enableSSL(SslHandlerProvider sslHandlerProvider) { diff --git a/src/main/java/org/logstash/plugins/inputs/http/HttpServerHandler.java b/src/main/java/org/logstash/plugins/inputs/http/HttpServerHandler.java index 36c1b291..6f6b603c 100644 --- a/src/main/java/org/logstash/plugins/inputs/http/HttpServerHandler.java +++ b/src/main/java/org/logstash/plugins/inputs/http/HttpServerHandler.java @@ -23,19 +23,21 @@ public class HttpServerHandler extends SimpleChannelInboundHandler stringHeaders) { response.headers().set(headers); if (responseStatus != HttpResponseStatus.NO_CONTENT) { - final ByteBuf payload = Unpooled.wrappedBuffer("ok".getBytes(charset)); + final ByteBuf payload = Unpooled.wrappedBuffer(this.responseBody.getBytes(charset)); response.headers().set(HttpHeaderNames.CONTENT_LENGTH, payload.readableBytes()); - response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain"); response.content().writeBytes(payload); } diff --git a/src/main/java/org/logstash/plugins/inputs/http/NettyHttpServer.java b/src/main/java/org/logstash/plugins/inputs/http/NettyHttpServer.java index 12eb7945..e3365d5b 100644 --- a/src/main/java/org/logstash/plugins/inputs/http/NettyHttpServer.java +++ b/src/main/java/org/logstash/plugins/inputs/http/NettyHttpServer.java @@ -32,7 +32,8 @@ public class NettyHttpServer implements Runnable, Closeable { public NettyHttpServer(String host, int port, IMessageHandler messageHandler, SslHandlerProvider sslHandlerProvider, int threads, - int maxPendingRequests, int maxContentLength, int responseCode) + int maxPendingRequests, int maxContentLength, int responseCode, + String responseBody) { this.host = host; this.port = port; @@ -44,7 +45,7 @@ public NettyHttpServer(String host, int port, IMessageHandler messageHandler, new CustomRejectedExecutionHandler()); final HttpInitializer httpInitializer = new HttpInitializer(messageHandler, executorGroup, - maxContentLength, responseStatus); + maxContentLength, responseStatus, responseBody); if (sslHandlerProvider != null) { httpInitializer.enableSSL(sslHandlerProvider);