NettyHttpServiceClient implements ServiceClient { private void sendHttpRequest(Operation op) { final Object originalBody = op.getBodyRaw(); try { byte[] body = Utils.encodeBody(op, true); if (op.getContentLength() > getRequestPayloadSizeLimit()) { String error = String.format("Content length %d, limit is %d", op.getContentLength(), getRequestPayloadSizeLimit()); Exception e = new IllegalArgumentException(error); op.setBody(ServiceErrorResponse.create(e, Operation.STATUS_CODE_BAD_REQUEST)); fail(e, op, originalBody); return; } String pathAndQuery; String path = op.getUri().getPath(); String query = op.getUri().getRawQuery(); String userInfo = op.getUri().getRawUserInfo(); path = path == null || path.isEmpty() ? "/" : path; if (query != null) { pathAndQuery = path + "?" + query; } else { pathAndQuery = path; } boolean useHttp2 = op.isConnectionSharing(); if (this.httpProxy != null || useHttp2 || userInfo != null) { pathAndQuery = op.getUri().toString(); } NettyFullHttpRequest request = null; HttpMethod method = toHttpMethod(op.getAction()); if (body == null || body.length == 0) { request = new NettyFullHttpRequest(HttpVersion.HTTP_1_1, method, pathAndQuery, Unpooled.EMPTY_BUFFER, false); } else { ByteBuf content = Unpooled.wrappedBuffer(body, 0, (int) op.getContentLength()); request = new NettyFullHttpRequest(HttpVersion.HTTP_1_1, method, pathAndQuery, content, false); } HttpHeaders httpHeaders = request.headers(); boolean hasRequestHeaders = op.hasRequestHeaders(); if (useHttp2) { if (hasRequestHeaders) { op.getAndRemoveRequestHeaderAsIs(Operation.STREAM_ID_HEADER); } request.setOperation(op); } String pragmaValue = op.getAndRemoveRequestHeaderAsIs(Operation.PRAGMA_HEADER); String acceptValue = op.getAndRemoveRequestHeaderAsIs(Operation.ACCEPT_HEADER); String authTokenValue = op .getAndRemoveRequestHeaderAsIs(Operation.REQUEST_AUTH_TOKEN_HEADER); if (op.isFromReplication() && pragmaValue == null) { httpHeaders.add(HttpHeaderNames.PRAGMA, PRAGMA_DIRECTIVE_REPLICATED_ASCII); } else if (pragmaValue != null) { httpHeaders.add(HttpHeaderNames.PRAGMA, pragmaValue); } if (op.getTransactionId() != null) { httpHeaders.add(TRANSACTION_ID_HEADER_ASCII, op.getTransactionId()); } if (op.getContextId() != null) { httpHeaders.add(CONTEXT_ID_HEADER_ASCII, op.getContextId()); } hasRequestHeaders = op.hasRequestHeaders(); String connectionHeaderValue = op.getRequestHeaderAsIs(Operation.CONNECTION_HEADER); boolean isXenonToXenon = op.isFromReplication() || op.isForwarded(); if (hasRequestHeaders) { op.getAndRemoveRequestHeaderAsIs(Operation.CONTENT_LENGTH_HEADER); op.getAndRemoveRequestHeaderAsIs(Operation.CONTENT_TYPE_HEADER); op.getAndRemoveRequestHeaderAsIs(Operation.CONNECTION_HEADER); op.getAndRemoveRequestHeaderAsIs(Operation.REFERER_HEADER); op.getAndRemoveRequestHeaderAsIs(Operation.HOST_HEADER); op.getAndRemoveRequestHeaderAsIs(Operation.USER_AGENT_HEADER); hasRequestHeaders = op.hasRequestHeaders(); } if (hasRequestHeaders) { for (Entry<String, String> nameValue : op.getRequestHeaders().entrySet()) { httpHeaders.add(nameValue.getKey(), nameValue.getValue()); } } if (authTokenValue != null) { httpHeaders.add(AUTH_TOKEN_HEADER_ASCII, authTokenValue); } else { AuthorizationContext ctx = op.getAuthorizationContext(); if (ctx != null && ctx.getToken() != null) { httpHeaders.add(AUTH_TOKEN_HEADER_ASCII, ctx.getToken()); } } setAsciiContentType(op, httpHeaders); httpHeaders.add(HttpHeaderNames.CONTENT_LENGTH, Long.toString(op.getContentLength())); if (op.isKeepAlive()) { httpHeaders.add(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE); } else if (connectionHeaderValue != null) { httpHeaders.add(HttpHeaderNames.CONNECTION, connectionHeaderValue); } if (op.hasReferer() && !op.isFromReplication()) { httpHeaders.add(HttpHeaderNames.REFERER, op.getRefererAsString()); } if (!isXenonToXenon) { if (op.getCookies() != null) { String header = CookieJar.encodeCookies(op.getCookies()); httpHeaders.set(HttpHeaderNames.COOKIE, header); } request.headers().set(HttpHeaderNames.USER_AGENT, this.userAgentAscii); if (acceptValue == null) { httpHeaders.add(HttpHeaderNames.ACCEPT, DEFAULT_MEDIA_TYPE_ASCII); } else { httpHeaders.add(HttpHeaderNames.ACCEPT, acceptValue); } httpHeaders.add(HttpHeaderNames.HOST, op.getUri().getHost()); } else { if (acceptValue != null) { httpHeaders.add(HttpHeaderNames.ACCEPT, acceptValue); } } if (LOGGER.isLoggable(Level.FINEST)) { logRequestFraming(op, request); } boolean doCookieJarUpdate = !isXenonToXenon; op.nestCompletion((o, e) -> { if (e != null) { fail(e, op, originalBody); return; } stopTracking(op); if (doCookieJarUpdate) { updateCookieJarFromResponseHeaders(o); } op.complete(); }); op.toggleOption(OperationOption.SOCKET_ACTIVE, true); op.getSocketContext().writeHttpRequest(request); } catch (Exception e) { op.setBody(ServiceErrorResponse.create(e, Operation.STATUS_CODE_BAD_REQUEST, EnumSet.of(ErrorDetail.SHOULD_RETRY))); fail(e, op, originalBody); } }  static ServiceClient create(String userAgent,
            ExecutorService executor,
            ScheduledExecutorService scheduledExecutor); static ServiceClient create(String userAgent,
            ExecutorService executor,
            ScheduledExecutorService scheduledExecutor,
            ServiceHost host); @Override void start(); @Override void stop(); ServiceClient setHttpProxy(URI proxy); @Override void send(Operation op); @Override void sendRequest(Operation op); @Override void handleMaintenance(Operation op); @Override ServiceClient setPendingRequestQueueLimit(int limit); @Override int getPendingRequestQueueLimit(); @Override ServiceClient setConnectionLimitPerTag(String tag, int limit); @Override int getConnectionLimitPerTag(String tag); ServiceClient setHttp2SslContext(SslContext context); SslContext getHttp2SslContext(); @Override ServiceClient setSSLContext(SSLContext context); @Override SSLContext getSSLContext(); NettyChannelPool getChannelPool(); NettyChannelPool getHttp2ChannelPool(); NettyChannelPool getSslChannelPool(); NettyChannelContext getInUseHttp2SslContext(String tag, String host, int port); NettyChannelContext getInUseHttp2Context(String tag, String host, int port); @Override ConnectionPoolMetrics getConnectionPoolMetrics(boolean http2); @Override ConnectionPoolMetrics getConnectionPoolMetricsPerTag(String tag); int getInUseContextCount(String tag, String host, int port); void clearCookieJar(); @Override int getRequestPayloadSizeLimit(); @Override ServiceClient setRequestPayloadSizeLimit(int limit); static final int DEFAULT_CONNECTIONS_PER_HOST; static final Logger LOGGER; }
@Test public void throughputPostRemote() throws Throwable { if (this.testURI == null) { return; } this.host.setOperationTimeOutMicros(TimeUnit.SECONDS.toMicros(120)); this.host.setTimeoutSeconds(120); this.host.log( "Starting HTTP POST stress test against %s, request count: %d, connection limit: %d", this.testURI, this.requestCount, this.connectionCount); long start = System.nanoTime(); ExampleServiceState body = new ExampleServiceState(); body.name = UUID.randomUUID().toString(); this.host.sendHttpRequest(this.host.getClient(), this.testURI, Utils.toJson(body), this.requestCount); long end = System.nanoTime(); double thpt = this.requestCount / ((end - start) / (double) TimeUnit.SECONDS.toNanos(1)); this.host.log("Connection limit: %d, Request count: %d, Requests per second:%f", this.connectionCount, this.requestCount, thpt); }