title: Identical request timing out in Java Apache, working fine in postman
body: <p>I'm trying to register a Office365 Api webhook per <a href="https://docs.microsoft.com/en-us/previous-versions/office/office-365-api/api/version-2.0/notify-rest-operations#SubscribeOperation" rel="noreferrer">official api docs</a>. I tried it in postman, all works as expected.</p>
  
  <p>Java Version: 1.7 (I know...)</p>
  
  <p>I am working with the Play framework version 1.2.7.2</p>
  
  <p>HttpClient: <code>org.apache.http.client.HttpClient</code></p>
  
  <p>Relevant documentation:</p>
  
  <blockquote>
    <p>The subscription process goes as follows:</p>
    
    <p>A client app makes a subscription request (POST) for a specific resource. It includes a notification URL, among other properties.</p>
    
    <p>The Outlook notifications service tries to validate the notification URL with the listener service. It includes a validation token in the validation request.</p>
    
    <p>If the listener service successfully validates the URL, it returns a success response within 5 seconds as follows:</p>
    
    <p>Sets the content type in the response header to text\plain.
    Includes the same validation token in the response body.
    Returns an HTTP 200 response code. The listener can discard the validation token subsequently.
    Depending on the URL validation result, the Outlook notifications service sends a response to the client app:</p>
    
    <p>If URL validation was successful, the service creates the subscription with a unique subscription ID and sends the response to the client.
    If URL validation was unsuccessful, the service sends an error response with an error code and other details.
    Upon receiving a successful response, the client app stores the subscription ID to correlate future notifications with this subscription.</p>
  </blockquote>
  
  <p>Postman request:</p>
  
  <p>Both requests intercepted with wireshark:</p>
  
  <p>Postman:</p>
  
  <pre><code>Ý`!Ë2@Ê¸1cÊþßV:
  ðîPOST /api/v2.0/me/subscriptions HTTP/1.1
  Content-Type: application/json
  cache-control: no-cache
  Postman-Token: a24df796-c49e-4245-a1cf-0949cd6538b6
  Authorization: Bearer ###
  User-Agent: PostmanRuntime/7.4.0
  Accept: */*
  Host: localhost:3000
  accept-encoding: gzip, deflate
  content-length: 430
  Connection: keep-alive
  
  {
      "@odata.type":"#Microsoft.OutlookServices.PushSubscription",
      "ChangeType": "Created, Deleted, Updated",
      "ClientState": "some-token",
      "NotificationURL": "https://###/office365/receive.php?subId=5",
      "Resource": "https://outlook.office.com/api/v2.0/me/Calendars('###')/events"
  }
  </code></pre>
  
  <p>(captured in wireshark) (the <code>###</code> parts are removed info, I made sure that auth and ids match up)</p>
  
  <p>At <code>###/office365/receive.php</code> lies a php script which just echoes back <code>$_GET['validationtoken']</code>. This works perfectly in Postman.</p>
  
  <p>In Java, I create a request with the same headers and the same body</p>
  
  <pre><code>E/@@5â$¸³zêð-gÄV$
  Là¼Là¼POST /api/v2.0/me/subscriptions HTTP/1.1
  Accept: */*
  Content-Type: application/json
  Authorization: Bearer ###
  Content-Length: 476
  Host: localhost:3000
  Connection: Keep-Alive
  User-Agent: Apache-HttpClient/4.5.2 (Java/1.7.0_80)
  Accept-Encoding: gzip,deflate
  
  {
      "@odata.type":"#Microsoft.OutlookServices.PushSubscription",
      "ChangeType": "Created, Deleted, Updated",
      "ClientState": "1fdb3e372212622e0b7e68abe09e1201a81a8bcc040cce9a6f013f71a09bfbe1",
      "NotificationURL": "https://###/office365/receive.php",
      "Resource": "https://outlook.office.com/api/v2.0/me/Calendars('###')/events"
  }
  </code></pre>
  
  <p>I verified that all (important) parts of the request are exactly the same.</p>
  
  <p>My code in java is a little to complex to share fully here, however the important bits are:</p>
  
  <pre><code>// build url
  private final RequestBuilder getRequest (String url) {
      RequestBuilder req  = RequestBuilder.create(getMethod()); // e.g. POST
      req.setUri(overwriteBaseUrl(url) + getPath());
  
      // headers is a hashmap&lt;String, String&gt;
      for (String key: headers.keySet()) {
          req.setHeader(key, headers.get(key));
      }
  
      // set body (handle empty cases)
      String body = getBody();
      if (body == null) {
          body = "";
      }
  
      req.setEntity(new StringEntity(body, "UTF-8"));
  
      return req;
  }
  
  public void send (HttpClient client, Office365Credentials cred, String url) throws IOException, InvalidCrmCredentialsException, MalformedResponseException {
      // creates request (with headers, body, etc)
      RequestBuilder req = getRequest(url);
      // adds auth
      addAuthHeaderToRequest(cred, req);
  
      // execute the request
      Response response;
      try {
           response = new Response(client.execute(req.build()));
      } catch (ConnectionPoolTimeoutException e) {
          // The 10 second limit has passed
          throw new MalformedResponseException("Response missing (response timed out)!", e);
      }
  
      // check for 401, not authorized
      if (response.getStatus() == 401) {
          throw new InvalidCrmCredentialsException("401 - Not authorized! " + req.getUri().toString());
      }
  
      // process response
      processResponse(response);
  }
  </code></pre>
  
  <p>The HttpClient is constructed like this:</p>
  
  <pre><code>    int CONNECTION_TIMEOUT_MS = 10 * 1000; // 10 second timeout
      RequestConfig requestConfig = RequestConfig.custom()
              .setConnectionRequestTimeout(CONNECTION_TIMEOUT_MS)
              .setConnectTimeout(CONNECTION_TIMEOUT_MS)
              .setSocketTimeout(CONNECTION_TIMEOUT_MS)
              .build();
  
      client = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig).build();
  </code></pre>
  
  <p>No matter how high I set the limit, I never get a response, the office api. Not even an error response.</p>
  
  <p>TL;DR: My request works fine in postman, exact same request in Java times out (no matter the timeout length)</p>