@Override public void send(final TransportListener listener, final Message.Mutable... messages) { String url = getURL(); final URI uri = URI.create(url); if (_appendMessageType && messages.length == 1 && messages[0].isMeta()) { String type = messages[0].getChannel().substring(Channel.META.length()); if (url.endsWith("/")) url = url.substring(0, url.length() - 1); url += type; } final Request request = _httpClient.newRequest(url).method(HttpMethod.POST); request.header(HttpHeader.CONTENT_TYPE.asString(), "application/json;charset=UTF-8"); StringBuilder builder = new StringBuilder(); for (HttpCookie cookie : getCookieStore().get(uri)) { builder.setLength(0); builder.append(cookie.getName()).append("=").append(cookie.getValue()); request.header(HttpHeader.COOKIE.asString(), builder.toString()); } request.content(new StringContentProvider(generateJSON(messages))); customize(request); synchronized (this) { if (_aborted) throw new IllegalStateException("Aborted"); _requests.add(request); } request.listener( new Request.Listener.Empty() { @Override public void onHeaders(Request request) { listener.onSending(messages); } }); long maxNetworkDelay = _maxNetworkDelay; if (messages.length == 1 && Channel.META_CONNECT.equals(messages[0].getChannel())) { Map<String, Object> advice = messages[0].getAdvice(); if (advice == null) advice = _advice; if (advice != null) { Object timeout = advice.get("timeout"); if (timeout instanceof Number) maxNetworkDelay += ((Number) timeout).longValue(); else if (timeout != null) maxNetworkDelay += Long.parseLong(timeout.toString()); } } // Set the idle timeout for this request larger than the total timeout // so there are no races between the two timeouts request.idleTimeout(maxNetworkDelay * 2, TimeUnit.MILLISECONDS); request.timeout(maxNetworkDelay, TimeUnit.MILLISECONDS); request.send( new BufferingResponseListener() { @Override public boolean onHeader(Response response, HttpField field) { // We do not allow cookies to be handled by HttpClient, since one // HttpClient instance is shared by multiple BayeuxClient instances. // Instead, we store the cookies in the BayeuxClient instance. switch (field.getHeader()) { case SET_COOKIE: case SET_COOKIE2: Map<String, List<String>> cookies = new HashMap<>(1); cookies.put(field.getName(), Collections.singletonList(field.getValue())); storeCookies(uri, cookies); return false; default: return true; } } private void storeCookies(URI uri, Map<String, List<String>> cookies) { try { _cookieManager.put(uri, cookies); } catch (IOException x) { logger.debug("", x); } } @Override public void onComplete(Result result) { synchronized (LongPollingTransport.this) { _requests.remove(result.getRequest()); } if (result.isFailed()) { listener.onFailure(result.getFailure(), messages); return; } Response response = result.getResponse(); int status = response.getStatus(); if (status == HttpStatus.OK_200) { String content = getContentAsString(); if (content != null && content.length() > 0) { try { List<Message.Mutable> messages = parseMessages(content); debug("Received messages {}", messages); for (Message.Mutable message : messages) { if (message.isSuccessful() && Channel.META_CONNECT.equals(message.getChannel())) { Map<String, Object> advice = message.getAdvice(); if (advice != null && advice.get("timeout") != null) _advice = advice; } } listener.onMessages(messages); } catch (ParseException x) { listener.onFailure(x, messages); } } else { Map<String, Object> failure = new HashMap<>(2); // Convert the 200 into 204 (no content) failure.put("httpCode", 204); TransportException x = new TransportException(failure); listener.onFailure(x, messages); } } else { Map<String, Object> failure = new HashMap<>(2); failure.put("httpCode", status); TransportException x = new TransportException(failure); listener.onFailure(x, messages); } } }); }