All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ratpack.http.internal.DefaultResponse Maven / Gradle / Ivy

There is a newer version: 2.0.0-rc-1
Show newest version
/*
 * Copyright 2013 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 ratpack.http.internal;

import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.handler.codec.http.*;
import io.netty.util.CharsetUtil;
import org.reactivestreams.Publisher;
import ratpack.api.Nullable;
import ratpack.exec.ExecControl;
import ratpack.file.internal.ResponseTransmitter;
import ratpack.func.Action;
import ratpack.http.*;
import ratpack.util.ExceptionUtils;
import ratpack.util.MultiValueMap;

import java.nio.CharBuffer;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.function.Supplier;

import static ratpack.file.internal.DefaultFileRenderer.readAttributes;
import static ratpack.http.internal.HttpHeaderConstants.CONTENT_TYPE;

public class DefaultResponse implements Response {

  private HttpResponseStatus status = HttpResponseStatus.OK;
  private final MutableHeaders headers;
  private final ExecControl execControl;
  private final ByteBufAllocator byteBufAllocator;
  private final ResponseTransmitter responseTransmitter;

  private boolean contentTypeSet;
  private Set cookies;
  private List> responseFinalizers;

  public DefaultResponse(ExecControl execControl, MutableHeaders headers, ByteBufAllocator byteBufAllocator, ResponseTransmitter responseTransmitter) {
    this.execControl = execControl;
    this.byteBufAllocator = byteBufAllocator;
    this.responseTransmitter = responseTransmitter;
    this.headers = new MutableHeadersWrapper(headers);
    responseFinalizers = Lists.newArrayList();
  }

  class MutableHeadersWrapper implements MutableHeaders {

    private final MutableHeaders wrapped;

    MutableHeadersWrapper(MutableHeaders wrapped) {
      this.wrapped = wrapped;
    }

    @Override
    public MutableHeaders add(CharSequence name, Object value) {
      if (!contentTypeSet && (name == CONTENT_TYPE || name.toString().equalsIgnoreCase(CONTENT_TYPE.toString()))) {
        contentTypeSet = true;
      }

      wrapped.add(name, value);
      return this;
    }

    @Override
    public MutableHeaders set(CharSequence name, Object value) {
      if (!contentTypeSet && (name == CONTENT_TYPE || name.toString().equalsIgnoreCase(CONTENT_TYPE.toString()))) {
        contentTypeSet = true;
      }

      wrapped.set(name, value);
      return this;
    }

    @Override
    public MutableHeaders setDate(CharSequence name, Date value) {
      wrapped.set(name, value);
      return this;
    }

    @Override
    public MutableHeaders set(CharSequence name, Iterable values) {
      if (!contentTypeSet && (name == CONTENT_TYPE || name.toString().equalsIgnoreCase(CONTENT_TYPE.toString()))) {
        contentTypeSet = true;
      }

      wrapped.set(name, values);
      return this;
    }

    @Override
    public MutableHeaders remove(CharSequence name) {
      if (name == CONTENT_TYPE || name.toString().equalsIgnoreCase(CONTENT_TYPE.toString())) {
        contentTypeSet = false;
      }

      wrapped.remove(name);
      return this;
    }

    @Override
    public MutableHeaders clear() {
      contentTypeSet = false;
      wrapped.clear();
      return this;
    }

    @Override
    public MutableHeaders copy(Headers headers) {
      this.wrapped.copy(headers);
      if (headers.contains(HttpHeaderConstants.CONTENT_TYPE)) {
        contentTypeSet = true;
      }
      return this;
    }

    @Override
    public MultiValueMap asMultiValueMap() {
      return wrapped.asMultiValueMap();
    }

    @Nullable
    @Override
    public String get(CharSequence name) {
      return wrapped.get(name);
    }

    @Nullable
    @Override
    public String get(String name) {
      return wrapped.get(name);
    }

    @Nullable
    @Override
    public Date getDate(CharSequence name) {
      return wrapped.getDate(name);
    }

    @Override
    @Nullable
    public Date getDate(String name) {
      return wrapped.getDate(name);
    }

    @Override
    public List getAll(CharSequence name) {
      return wrapped.getAll(name);
    }

    @Override
    public List getAll(String name) {
      return wrapped.getAll(name);
    }

    @Override
    public boolean contains(CharSequence name) {
      return wrapped.contains(name);
    }

    @Override
    public boolean contains(String name) {
      return wrapped.contains(name);
    }

    @Override
    public Set getNames() {
      return wrapped.getNames();
    }

    @Override
    public HttpHeaders getNettyHeaders() {
      return wrapped.getNettyHeaders();
    }
  }

  public Status getStatus() {
    return new DefaultStatus(status);
  }

  public Response status(int code) {
    status = HttpResponseStatus.valueOf(code);
    return this;
  }

  @Override
  public Response status(Status status) {
    return status(status.getCode());
  }

  @Override
  public MutableHeaders getHeaders() {
    return headers;
  }

  public void send() {
    commit(byteBufAllocator.buffer(0, 0));
  }

  @Override
  public Response contentTypeIfNotSet(Supplier contentType) {
    if (!contentTypeSet) {
      contentType(contentType.get());
    }
    return this;
  }

  @Override
  public Response contentType(CharSequence contentType) {
    headers.set(CONTENT_TYPE, contentType);
    return this;
  }

  public void send(String text) {
    ByteBuf byteBuf = ByteBufUtil.encodeString(byteBufAllocator, CharBuffer.wrap(text), CharsetUtil.UTF_8);
    contentTypeIfNotSet(HttpHeaderConstants.PLAIN_TEXT_UTF8).send(byteBuf);
  }

  public void send(CharSequence contentType, String body) {
    contentType(contentType);
    send(body);
  }

  public void send(byte[] bytes) {
    contentTypeIfNotSet(HttpHeaderConstants.OCTET_STREAM);
    commit(Unpooled.wrappedBuffer(bytes));
  }

  public void send(CharSequence contentType, byte[] bytes) {
    contentType(contentType).send(bytes);
  }

  public void send(CharSequence contentType, ByteBuf buffer) {
    contentType(contentType);
    send(buffer);
  }

  public void send(ByteBuf buffer) {
    contentTypeIfNotSet(HttpHeaderConstants.OCTET_STREAM);
    commit(buffer);
  }

  @Override
  public void sendFile(BasicFileAttributes attributes, Path file) {
    finalizeResponse();
    setCookieHeader();
    responseTransmitter.transmit(status, attributes, file);
  }

  @Override
  public void sendStream(Publisher stream) {
    finalizeResponse();
    setCookieHeader();
    stream.subscribe(responseTransmitter.transmitter(status));
  }

  @Override
  public Response beforeSend(Action responseFinalizer) {
    responseFinalizers.add(responseFinalizer);
    return this;
  }

  public void sendFile(final Path file) {
    try {
      readAttributes(execControl, file, fileAttributes -> sendFile(fileAttributes, file));
    } catch (Exception e) {
      // Shouldn't happen
      throw ExceptionUtils.uncheck(e);
    }
  }

  public Set getCookies() {
    if (cookies == null) {
      cookies = Sets.newHashSet();
    }
    return cookies;
  }

  public Cookie cookie(String name, String value) {
    Cookie cookie = new DefaultCookie(name, value);
    getCookies().add(cookie);
    return cookie;
  }

  public Cookie expireCookie(String name) {
    Cookie cookie = cookie(name, "");
    cookie.setMaxAge(0);
    return cookie;
  }

  private void setCookieHeader() {
    if (cookies != null && !cookies.isEmpty()) {
      for (Cookie cookie : cookies) {
        headers.add(HttpHeaderConstants.SET_COOKIE, ServerCookieEncoder.encode(cookie));
      }
    }
  }

  private void commit(ByteBuf byteBuf) {
    finalizeResponse();
    setCookieHeader();
    responseTransmitter.transmit(status, byteBuf);
  }

  private void finalizeResponse() {
    for (Action responseFinalizer : responseFinalizers) {
      try {
        responseFinalizer.execute(this);
      } catch (Exception e) {
        throw ExceptionUtils.uncheck(e);
      }
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy