示例#1
0
  @Override
  public boolean sendMessageToEndPoint(final HttpMessage message) {
    Assert.notNull(this.httpClient);

    try {
      final HttpPost request = new HttpPost(message.getUrl().toURI());
      request.addHeader("Content-Type", message.getContentType());

      final StringEntity entity =
          new StringEntity(message.getMessage(), ContentType.create(message.getContentType()));
      request.setEntity(entity);

      final ResponseHandler<Boolean> handler =
          response -> response.getStatusLine().getStatusCode() == HttpStatus.SC_OK;
      final HttpRequestFutureTask<Boolean> task =
          this.requestExecutorService.execute(request, HttpClientContext.create(), handler);
      if (message.isAsynchronous()) {
        return true;
      }
      return task.get();
    } catch (final RejectedExecutionException e) {
      LOGGER.warn(e.getMessage(), e);
      return false;
    } catch (final Exception e) {
      LOGGER.debug(e.getMessage(), e);
      return false;
    }
  }
示例#2
0
 /**
  * Sets or removes the {@code "Expect: 100-continue"} header to / from the specified message. If
  * the specified {@code value} is {@code true}, the {@code "Expect: 100-continue"} header is set
  * and all other previous {@code "Expect"} headers are removed. Otherwise, all {@code "Expect"}
  * headers are removed completely.
  */
 public static void set100ContinueExpected(HttpMessage message, boolean set) {
   if (set) {
     message.headers().set(Names.EXPECT, Values.CONTINUE);
   } else {
     message.headers().remove(Names.EXPECT);
   }
 }
示例#3
0
 /** Sets the {@code "Date"} header. */
 public static void setDate(HttpMessage message, Date value) {
   if (value != null) {
     message.headers().set(Names.DATE, HttpHeaderDateFormat.get().format(value));
   } else {
     message.headers().set(Names.DATE, null);
   }
 }
示例#4
0
 /**
  * Sets a new date header with the specified name and value. If there is an existing header with
  * the same name, the existing header is removed. The specified value is formatted as defined in
  * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>
  */
 public static void setDateHeader(HttpMessage message, CharSequence name, Date value) {
   if (value != null) {
     message.headers().set(name, HttpHeaderDateFormat.get().format(value));
   } else {
     message.headers().set(name, null);
   }
 }
示例#5
0
 public static void checkRequestHasContentLengthOrChunkedEncoding(
     HttpMessage request, String message) {
   boolean chunked = "chunked".equals(request.getFirstHeaderOrNull("Transfer-Encoding"));
   checkArgument(
       request.getPayload() == null
           || chunked
           || request.getPayload().getContentMetadata().getContentLength() != null,
       message);
 }
示例#6
0
 public static Long attemptToParseSizeAndRangeFromHeaders(HttpMessage from) throws HttpException {
   String contentRange = from.getFirstHeaderOrNull("Content-Range");
   if (contentRange == null && from.getPayload() != null) {
     return from.getPayload().getContentMetadata().getContentLength();
   } else if (contentRange != null) {
     return Long.parseLong(contentRange.substring(contentRange.lastIndexOf('/') + 1));
   }
   return null;
 }
示例#7
0
  /**
   * Returns {@code true} if and only if the connection can remain open and thus 'kept alive'. This
   * methods respects the value of the {@code "Connection"} header first and then the return value
   * of {@link HttpVersion#isKeepAliveDefault()}.
   */
  public static boolean isKeepAlive(HttpMessage message) {
    String connection = message.headers().get(Names.CONNECTION);
    if (connection != null && equalsIgnoreCase(Values.CLOSE, connection)) {
      return false;
    }

    if (message.getProtocolVersion().isKeepAliveDefault()) {
      return !equalsIgnoreCase(Values.CLOSE, connection);
    } else {
      return equalsIgnoreCase(Values.KEEP_ALIVE, connection);
    }
  }
示例#8
0
 /**
  * Returns the header value with the specified header name. If there are more than one header
  * value for the specified header name, the first value is returned.
  *
  * @return the header value or the {@code defaultValue} if there is no such header
  */
 public static String getHeader(HttpMessage message, CharSequence name, String defaultValue) {
   String value = message.headers().get(name);
   if (value == null) {
     return defaultValue;
   }
   return value;
 }
示例#9
0
 /**
  * Sets the value of the {@code "Connection"} header depending on the protocol version of the
  * specified message. This getMethod sets or removes the {@code "Connection"} header depending on
  * what the default keep alive mode of the message's protocol version is, as specified by {@link
  * HttpVersion#isKeepAliveDefault()}.
  *
  * <ul>
  *   <li>If the connection is kept alive by default:
  *       <ul>
  *         <li>set to {@code "close"} if {@code keepAlive} is {@code false}.
  *         <li>remove otherwise.
  *       </ul>
  *   <li>If the connection is closed by default:
  *       <ul>
  *         <li>set to {@code "keep-alive"} if {@code keepAlive} is {@code true}.
  *         <li>remove otherwise.
  *       </ul>
  * </ul>
  */
 public static void setKeepAlive(HttpMessage message, boolean keepAlive) {
   HttpHeaders h = message.headers();
   if (message.getProtocolVersion().isKeepAliveDefault()) {
     if (keepAlive) {
       h.remove(Names.CONNECTION);
     } else {
       h.set(Names.CONNECTION, Values.CLOSE);
     }
   } else {
     if (keepAlive) {
       h.set(Names.CONNECTION, Values.KEEP_ALIVE);
     } else {
       h.remove(Names.CONNECTION);
     }
   }
 }
示例#10
0
 private OAuthAccessToken parseUrlEncodedToken(HttpMessage response) {
   Map<String, String[]> params = new HashMap<String, String[]>();
   AuthUtils.parseFormUrlEncoded(response, params);
   if (response.getStatus() == 200) {
     String accessTokenE = AuthUtils.getParamValue(params, "access_token");
     if (accessTokenE != null) {
       String accessToken = accessTokenE;
       WDate expires = null;
       String expiresE = AuthUtils.getParamValue(params, "expires");
       if (expiresE != null) {
         expires = new WDate(new Date()).addSeconds(Integer.parseInt(expiresE));
       }
       return new OAuthAccessToken(accessToken, expires, "");
     } else {
       throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService.badresponse"));
     }
   } else {
     String errorE = AuthUtils.getParamValue(params, "error");
     if (errorE != null) {
       throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService." + errorE));
     } else {
       throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService.badresponse"));
     }
   }
 }
示例#11
0
 public static void wirePayloadIfEnabled(Wire wire, HttpMessage request) {
   if (request.getPayload() != null && wire.enabled()) {
     wire.output(request);
     checkRequestHasContentLengthOrChunkedEncoding(
         request,
         "After wiring, the request has neither chunked encoding nor content length: " + request);
   }
 }
示例#12
0
 public static void removeTransferEncodingChunked(HttpMessage m) {
   List<String> values = m.headers().getAll(Names.TRANSFER_ENCODING);
   if (values.isEmpty()) {
     return;
   }
   Iterator<String> valuesIt = values.iterator();
   while (valuesIt.hasNext()) {
     String value = valuesIt.next();
     if (equalsIgnoreCase(value, Values.CHUNKED)) {
       valuesIt.remove();
     }
   }
   if (values.isEmpty()) {
     m.headers().remove(Names.TRANSFER_ENCODING);
   } else {
     m.headers().set(Names.TRANSFER_ENCODING, values);
   }
 }
示例#13
0
 @Override
 protected Object decode(ChannelHandlerContext ctx, HttpMessage msg) throws Exception {
   String acceptedEncoding = msg.headers().get(HttpHeaders.Names.ACCEPT_ENCODING);
   if (acceptedEncoding == null) {
     acceptedEncoding = HttpHeaders.Values.IDENTITY;
   }
   boolean offered = acceptEncodingQueue.offer(acceptedEncoding);
   assert offered;
   return msg;
 }
示例#14
0
 /**
  * Parses the response for a token request.
  *
  * <p>Throws a {@link TokenError} when the response indicates an error, or when the response could
  * not be properly parsed.
  *
  * <p>Some OAuth implementations may uses a non-standard encoding of the token.
  */
 protected OAuthAccessToken parseTokenResponse(HttpMessage response) {
   if (response.getStatus() == 200 || response.getStatus() == 400) {
     String type = response.getHeader("Content-Type");
     if (type != null) {
       if (type.startsWith("text/plain; charset=UTF-8")) {
         return this.parseUrlEncodedToken(response);
       } else {
         if (type.startsWith("application/json")) {
           return this.parseJsonToken(response);
         } else {
           throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService.badresponse"));
         }
       }
     } else {
       throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService.badresponse"));
     }
   } else {
     throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService.badresponse"));
   }
 }
示例#15
0
 void requestToken(String authorizationCode) {
   try {
     String url = this.service_.getTokenEndpoint();
     StringBuilder ss = new StringBuilder();
     ss.append("grant_type=authorization_code")
         .append("&client_id=")
         .append(Utils.urlEncode(this.service_.getClientId()))
         .append("&client_secret=")
         .append(Utils.urlEncode(this.service_.getClientSecret()))
         .append("&redirect_uri=")
         .append(Utils.urlEncode(this.service_.getGenerateRedirectEndpoint()))
         .append("&code=")
         .append(authorizationCode);
     HttpClient client = new HttpClient(this);
     client.setTimeout(15);
     client
         .done()
         .addListener(
             this,
             new Signal2.Listener<Exception, HttpMessage>() {
               public void trigger(Exception event1, HttpMessage event2) {
                 OAuthProcess.this.handleToken(event1, event2);
               }
             });
     Method m = this.service_.getTokenRequestMethod();
     if (m == Method.Get) {
       boolean hasQuery = url.indexOf('?') != -1;
       url += (hasQuery ? '&' : '?') + ss.toString();
       client.get(url);
     } else {
       HttpMessage post = new HttpMessage();
       post.setHeader("Content-Type", "application/x-www-form-urlencoded");
       post.addBodyText(ss.toString());
       client.post(url, post);
     }
   } catch (Exception e) {
     e.printStackTrace();
   }
 }
示例#16
0
 private OAuthAccessToken parseJsonToken(HttpMessage response) {
   com.google.gson.JsonObject root = new com.google.gson.JsonObject();
   com.google.gson.JsonParseException pe = null;
   try {
     root =
         (com.google.gson.JsonObject) new com.google.gson.JsonParser().parse(response.getBody());
   } catch (com.google.gson.JsonParseException error) {
     pe = error;
   }
   boolean ok = root != null;
   if (!ok) {
     logger.error(
         new StringWriter().append("parseJsonToken(): ").append(pe.toString()).toString());
     throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService.badjson"));
   } else {
     if (response.getStatus() == 200) {
       try {
         String accessToken = root.get("access_token").getAsString();
         int secs = JsonUtils.orIfNullInt(root.get("expires_in"), -1);
         WDate expires = null;
         if (secs > 0) {
           expires = new WDate(new Date()).addSeconds(secs);
         }
         String refreshToken = JsonUtils.orIfNullString(root.get("refreshToken"), "");
         return new OAuthAccessToken(accessToken, expires, refreshToken);
       } catch (RuntimeException e) {
         logger.error(
             new StringWriter().append("token response error: ").append(e.toString()).toString());
         throw new OAuthProcess.TokenError(WString.tr("Wt.Auth.OAuthService.badresponse"));
       }
     } else {
       throw new OAuthProcess.TokenError(
           WString.tr(
               "Wt.Auth.OAuthService."
                   + JsonUtils.orIfNullString(root.get("error"), "missing error")));
     }
   }
 }
示例#17
0
  /**
   * Returns {@code true} if and only if the specified message contains the {@code "Expect:
   * 100-continue"} header.
   */
  public static boolean is100ContinueExpected(HttpMessage message) {
    // Expect: 100-continue is for requests only.
    if (!(message instanceof HttpRequest)) {
      return false;
    }

    // It works only on HTTP/1.1 or later.
    if (message.getProtocolVersion().compareTo(HttpVersion.HTTP_1_1) < 0) {
      return false;
    }

    // In most cases, there will be one or zero 'Expect' header.
    String value = message.headers().get(Names.EXPECT);
    if (value == null) {
      return false;
    }
    if (equalsIgnoreCase(Values.CONTINUE, value)) {
      return true;
    }

    // Multiple 'Expect' headers.  Search through them.
    return message.headers().contains(Names.EXPECT, Values.CONTINUE, true);
  }
示例#18
0
  @Override
  public HttpMessage sendMessageToEndPoint(final URL url) {
    Assert.notNull(this.httpClient);

    HttpEntity entity = null;

    try (CloseableHttpResponse response = this.httpClient.execute(new HttpGet(url.toURI()))) {
      final int responseCode = response.getStatusLine().getStatusCode();

      for (final int acceptableCode : this.acceptableCodes) {
        if (responseCode == acceptableCode) {
          LOGGER.debug("Response code received from server matched {}.", responseCode);
          entity = response.getEntity();
          final HttpMessage msg =
              new HttpMessage(url, IOUtils.toString(entity.getContent(), StandardCharsets.UTF_8));
          msg.setContentType(entity.getContentType().getValue());
          msg.setResponseCode(responseCode);
          return msg;
        }
      }
      LOGGER.debug(
          "Response code did not match any of the acceptable response codes. Code returned {}",
          responseCode);
      if (responseCode == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
        final String value = response.getStatusLine().getReasonPhrase();
        LOGGER.error(
            "There was an error contacting the endpoint: {}; The error:\n{}",
            url.toExternalForm(),
            value);
      }
    } catch (final Exception e) {
      LOGGER.error(e.getMessage(), e);
    } finally {
      EntityUtils.consumeQuietly(entity);
    }
    return null;
  }
示例#19
0
  /**
   * Returns the length of the content. Please note that this value is not retrieved from {@link
   * HttpContent#content()} but from the {@code "Content-Length"} header, and thus they are
   * independent from each other.
   *
   * @return the content length or {@code defaultValue} if this message does not have the {@code
   *     "Content-Length"} header or its value is not a number
   */
  public static long getContentLength(HttpMessage message, long defaultValue) {
    String contentLength = message.headers().get(Names.CONTENT_LENGTH);
    if (contentLength != null) {
      try {
        return Long.parseLong(contentLength);
      } catch (NumberFormatException e) {
        return defaultValue;
      }
    }

    // We know the content length if it's a Web Socket message even if
    // Content-Length header is missing.
    long webSocketContentLength = getWebSocketContentLength(message);
    if (webSocketContentLength >= 0) {
      return webSocketContentLength;
    }

    // Otherwise we don't.
    return defaultValue;
  }
示例#20
0
  /**
   * Returns the content length of the specified web socket message. If the specified message is not
   * a web socket message, {@code -1} is returned.
   */
  private static int getWebSocketContentLength(HttpMessage message) {
    // WebSockset messages have constant content-lengths.
    HttpHeaders h = message.headers();
    if (message instanceof HttpRequest) {
      HttpRequest req = (HttpRequest) message;
      if (HttpMethod.GET.equals(req.getMethod())
          && h.contains(Names.SEC_WEBSOCKET_KEY1)
          && h.contains(Names.SEC_WEBSOCKET_KEY2)) {
        return 8;
      }
    } else if (message instanceof HttpResponse) {
      HttpResponse res = (HttpResponse) message;
      if (res.getStatus().code() == 101
          && h.contains(Names.SEC_WEBSOCKET_ORIGIN)
          && h.contains(Names.SEC_WEBSOCKET_LOCATION)) {
        return 16;
      }
    }

    // Not a web socket message
    return -1;
  }
示例#21
0
  @Override
  protected void decode(ChannelHandlerContext ctx, HttpObject msg, MessageBuf<Object> out)
      throws Exception {
    FullHttpMessage currentMessage = this.currentMessage;

    if (msg instanceof HttpMessage) {
      assert currentMessage == null;

      HttpMessage m = (HttpMessage) msg;

      // Handle the 'Expect: 100-continue' header if necessary.
      // TODO: Respond with 413 Request Entity Too Large
      //   and discard the traffic or close the connection.
      //       No need to notify the upstream handlers - just log.
      //       If decoding a response, just throw an exception.
      if (is100ContinueExpected(m)) {
        ctx.write(CONTINUE.duplicate());
      }

      if (!m.getDecoderResult().isSuccess()) {
        removeTransferEncodingChunked(m);
        this.currentMessage = null;
        out.add(BufUtil.retain(m));
        return;
      }
      if (msg instanceof HttpRequest) {
        HttpRequest header = (HttpRequest) msg;
        this.currentMessage =
            currentMessage =
                new DefaultFullHttpRequest(
                    header.getProtocolVersion(),
                    header.getMethod(),
                    header.getUri(),
                    Unpooled.compositeBuffer(maxCumulationBufferComponents));
      } else if (msg instanceof HttpResponse) {
        HttpResponse header = (HttpResponse) msg;
        this.currentMessage =
            currentMessage =
                new DefaultFullHttpResponse(
                    header.getProtocolVersion(),
                    header.getStatus(),
                    Unpooled.compositeBuffer(maxCumulationBufferComponents));
      } else {
        throw new Error();
      }

      currentMessage.headers().set(m.headers());

      // A streamed message - initialize the cumulative buffer, and wait for incoming chunks.
      removeTransferEncodingChunked(currentMessage);
    } else if (msg instanceof HttpContent) {
      assert currentMessage != null;

      // Merge the received chunk into the content of the current message.
      HttpContent chunk = (HttpContent) msg;
      CompositeByteBuf content = (CompositeByteBuf) currentMessage.content();

      if (content.readableBytes() > maxContentLength - chunk.content().readableBytes()) {
        // TODO: Respond with 413 Request Entity Too Large
        //   and discard the traffic or close the connection.
        //       No need to notify the upstream handlers - just log.
        //       If decoding a response, just throw an exception.
        throw new TooLongFrameException(
            "HTTP content length exceeded " + maxContentLength + " bytes.");
      }

      // Append the content of the chunk
      if (chunk.content().isReadable()) {
        chunk.retain();
        content.addComponent(chunk.content());
        content.writerIndex(content.writerIndex() + chunk.content().readableBytes());
      }

      final boolean last;
      if (!chunk.getDecoderResult().isSuccess()) {
        currentMessage.setDecoderResult(DecoderResult.failure(chunk.getDecoderResult().cause()));
        last = true;
      } else {
        last = chunk instanceof LastHttpContent;
      }

      if (last) {
        this.currentMessage = null;

        // Merge trailing headers into the message.
        if (chunk instanceof LastHttpContent) {
          LastHttpContent trailer = (LastHttpContent) chunk;
          currentMessage.headers().add(trailer.trailingHeaders());
        }

        // Set the 'Content-Length' header.
        currentMessage
            .headers()
            .set(HttpHeaders.Names.CONTENT_LENGTH, String.valueOf(content.readableBytes()));

        // All done
        out.add(currentMessage);
      }
    } else {
      throw new Error();
    }
  }
示例#22
0
 public static boolean isContentLengthSet(HttpMessage m) {
   return m.headers().contains(Names.CONTENT_LENGTH);
 }
示例#23
0
 /**
  * Sets a new integer header with the specified name and values. If there is an existing header
  * with the same name, the existing header is removed.
  */
 public static void setIntHeader(
     HttpMessage message, CharSequence name, Iterable<Integer> values) {
   message.headers().set(name, values);
 }
示例#24
0
 /**
  * Checks to see if the transfer encoding in a specified {@link HttpMessage} is chunked
  *
  * @param message The message to check
  * @return True if transfer encoding is chunked, otherwise false
  */
 public static boolean isTransferEncodingChunked(HttpMessage message) {
   return message.headers().contains(Names.TRANSFER_ENCODING, Values.CHUNKED, true);
 }
示例#25
0
 /** Adds a new integer header with the specified name and value. */
 public static void addIntHeader(HttpMessage message, CharSequence name, int value) {
   message.headers().add(name, value);
 }
示例#26
0
 /**
  * Sets a new date header with the specified name and values. If there is an existing header with
  * the same name, the existing header is removed. The specified values are formatted as defined in
  * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>
  */
 public static void setDateHeader(HttpMessage message, CharSequence name, Iterable<Date> values) {
   message.headers().set(name, values);
 }
示例#27
0
 /**
  * Adds a new date header with the specified name and value. The specified value is formatted as
  * defined in <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1">RFC2616</a>
  */
 public static void addDateHeader(HttpMessage message, CharSequence name, Date value) {
   message.headers().add(name, value);
 }
示例#28
0
 /** Sets the {@code "Host"} header. */
 public static void setHost(HttpMessage message, CharSequence value) {
   message.headers().set(Names.HOST, value);
 }
示例#29
0
 /** Returns the value of the {@code "Host"} header. */
 public static String getHost(HttpMessage message) {
   return message.headers().get(Names.HOST);
 }
示例#30
0
 /** Sets the {@code "Content-Length"} header. */
 public static void setContentLength(HttpMessage message, long length) {
   message.headers().set(Names.CONTENT_LENGTH, length);
 }