private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
    HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status);
    response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=UTF-8");
    response.setContent(
        ChannelBuffers.copiedBuffer(
            "Failure: " + status.toString() + "\r\n", Charset.forName("UTF-8")));

    // Close the connection as soon as the error message is sent.
    ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
  }
  @Override
  public void populateCamelHeaders(
      HttpResponse response,
      Map<String, Object> headers,
      Exchange exchange,
      NettyHttpConfiguration configuration)
      throws Exception {
    LOG.trace("populateCamelHeaders: {}", response);

    headers.put(Exchange.HTTP_RESPONSE_CODE, response.getStatus().getCode());
    headers.put(Exchange.HTTP_RESPONSE_TEXT, response.getStatus().getReasonPhrase());

    for (String name : response.headers().names()) {
      // mapping the content-type
      if (name.toLowerCase().equals("content-type")) {
        name = Exchange.CONTENT_TYPE;
      }
      // add the headers one by one, and use the header filter strategy
      List<String> values = response.headers().getAll(name);
      Iterator<?> it = ObjectHelper.createIterator(values);
      while (it.hasNext()) {
        Object extracted = it.next();
        LOG.trace("HTTP-header: {}", extracted);
        if (headerFilterStrategy != null
            && !headerFilterStrategy.applyFilterToExternalHeaders(name, extracted, exchange)) {
          NettyHttpHelper.appendHeader(headers, name, extracted);
        }
      }
    }
  }
Example #3
0
  public static Exception populateNettyHttpOperationFailedException(
      Exchange exchange,
      String url,
      HttpResponse response,
      int responseCode,
      boolean transferException) {
    String uri = url;
    String statusText = response.getStatus().getReasonPhrase();

    if (responseCode >= 300 && responseCode < 400) {
      String redirectLocation = response.headers().get("location");
      if (redirectLocation != null) {
        return new NettyHttpOperationFailedException(
            uri, responseCode, statusText, redirectLocation, response);
      } else {
        // no redirect location
        return new NettyHttpOperationFailedException(uri, responseCode, statusText, null, response);
      }
    }

    if (transferException) {
      String contentType = response.headers().get(Exchange.CONTENT_TYPE);
      if (NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) {
        // if the response was a serialized exception then use that
        InputStream is =
            exchange.getContext().getTypeConverter().convertTo(InputStream.class, response);
        if (is != null) {
          try {
            Object body = deserializeJavaObjectFromStream(is);
            if (body instanceof Exception) {
              return (Exception) body;
            }
          } catch (Exception e) {
            return e;
          } finally {
            IOHelper.close(is);
          }
        }
      }
    }

    // internal server error (error code 500)
    return new NettyHttpOperationFailedException(uri, responseCode, statusText, null, response);
  }
  private void sendHttpResponse(Channel channel, HttpRequest request, HttpResponse response) {
    if (!channel.isOpen()) {
      return;
    }

    // response的内容已在各Listener中填充
    response.headers().set(Names.CONTENT_LENGTH, response.getContent().readableBytes());
    response.headers().set(Names.SERVER, "NAVI/1.1.4(UNIX)");

    if (!HttpHeaders.isKeepAlive(request)
        || response.getStatus() != HttpResponseStatus.OK
        || ServerConfigure.isChannelClose()) {
      response.headers().set(Names.CONNECTION, "close");
      channel.setAttachment(WRITING);
      ChannelFuture f = channel.write(response);
      f.addListener(ChannelFutureListener.CLOSE);
      f.addListener(
          new ChannelFutureListener() {

            public void operationComplete(ChannelFuture f) throws Exception {
              if (!f.isSuccess()) {
                log.error(f.getCause().getMessage(), f.getCause());
              }
            }
          });
    } else {
      if (request.getProtocolVersion() == HttpVersion.HTTP_1_0) {
        response.headers().add(Names.CONNECTION, "Keep-Alive");
      }
      channel.setAttachment(WRITING);
      ChannelFuture f = channel.write(response);
      f.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
      f.addListener(
          new ChannelFutureListener() {

            public void operationComplete(ChannelFuture f) throws Exception {
              if (!f.isSuccess()) {
                log.error(f.getCause().getMessage(), f.getCause());
              }
            }
          });
    }
  }
  @Override
  public HttpResponse toNettyResponse(Message message, NettyHttpConfiguration configuration)
      throws Exception {
    LOG.trace("toNettyResponse: {}", message);

    // the message body may already be a Netty HTTP response
    if (message.getBody() instanceof HttpResponse) {
      return (HttpResponse) message.getBody();
    }

    // the response code is 200 for OK and 500 for failed
    boolean failed = message.getExchange().isFailed();
    int defaultCode = failed ? 500 : 200;

    int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, defaultCode, int.class);
    HttpResponse response =
        new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(code));
    LOG.trace("HTTP Status Code: {}", code);

    TypeConverter tc = message.getExchange().getContext().getTypeConverter();

    // append headers
    // must use entrySet to ensure case of keys is preserved
    for (Map.Entry<String, Object> entry : message.getHeaders().entrySet()) {
      String key = entry.getKey();
      Object value = entry.getValue();
      // use an iterator as there can be multiple values. (must not use a delimiter)
      final Iterator<?> it = ObjectHelper.createIterator(value, null);
      while (it.hasNext()) {
        String headerValue = tc.convertTo(String.class, it.next());
        if (headerValue != null
            && headerFilterStrategy != null
            && !headerFilterStrategy.applyFilterToCamelHeaders(
                key, headerValue, message.getExchange())) {
          LOG.trace("HTTP-Header: {}={}", key, headerValue);
          response.headers().add(key, headerValue);
        }
      }
    }

    Object body = message.getBody();
    Exception cause = message.getExchange().getException();
    // support bodies as native Netty
    ChannelBuffer buffer;

    // if there was an exception then use that as body
    if (cause != null) {
      if (configuration.isTransferException()) {
        // we failed due an exception, and transfer it as java serialized object
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(cause);
        oos.flush();
        IOHelper.close(oos, bos);

        // the body should be the serialized java object of the exception
        body = ChannelBuffers.copiedBuffer(bos.toByteArray());
        // force content type to be serialized java object
        message.setHeader(
            Exchange.CONTENT_TYPE, NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT);
      } else {
        // we failed due an exception so print it as plain text
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        cause.printStackTrace(pw);

        // the body should then be the stacktrace
        body = ChannelBuffers.copiedBuffer(sw.toString().getBytes());
        // force content type to be text/plain as that is what the stacktrace is
        message.setHeader(Exchange.CONTENT_TYPE, "text/plain");
      }

      // and mark the exception as failure handled, as we handled it by returning it as the response
      ExchangeHelper.setFailureHandled(message.getExchange());
    }

    if (body instanceof ChannelBuffer) {
      buffer = (ChannelBuffer) body;
    } else {
      // try to convert to buffer first
      buffer = message.getBody(ChannelBuffer.class);
      if (buffer == null) {
        // fallback to byte array as last resort
        byte[] data = message.getBody(byte[].class);
        if (data != null) {
          buffer = ChannelBuffers.copiedBuffer(data);
        } else {
          // and if byte array fails then try String
          String str;
          if (body != null) {
            str = message.getMandatoryBody(String.class);
          } else {
            str = "";
          }
          buffer = ChannelBuffers.copiedBuffer(str.getBytes());
        }
      }
    }
    if (buffer != null) {
      response.setContent(buffer);
      // We just need to reset the readerIndex this time
      if (buffer.readerIndex() == buffer.writerIndex()) {
        buffer.setIndex(0, buffer.writerIndex());
      }
      // TODO How to enable the chunk transport
      int len = buffer.readableBytes();
      // set content-length
      response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, len);
      LOG.trace("Content-Length: {}", len);
    }

    // set the content type in the response.
    String contentType = MessageHelper.getContentType(message);
    if (contentType != null) {
      // set content-type
      response.headers().set(HttpHeaders.Names.CONTENT_TYPE, contentType);
      LOG.trace("Content-Type: {}", contentType);
    }

    // configure connection to accordingly to keep alive configuration
    // favor using the header from the message
    String connection = message.getHeader(HttpHeaders.Names.CONNECTION, String.class);
    // Read the connection header from the exchange property
    if (connection == null) {
      connection = message.getExchange().getProperty(HttpHeaders.Names.CONNECTION, String.class);
    }
    if (connection == null) {
      // fallback and use the keep alive from the configuration
      if (configuration.isKeepAlive()) {
        connection = HttpHeaders.Values.KEEP_ALIVE;
      } else {
        connection = HttpHeaders.Values.CLOSE;
      }
    }
    response.headers().set(HttpHeaders.Names.CONNECTION, connection);
    // Just make sure we close the channel when the connection value is close
    if (connection.equalsIgnoreCase(HttpHeaders.Values.CLOSE)) {
      message.setHeader(NettyConstants.NETTY_CLOSE_CHANNEL_WHEN_COMPLETE, true);
    }
    LOG.trace("Connection: {}", connection);

    return response;
  }