protected HttpResponse sendHttpRequest(
      String method, String url, HttpEntity entity, List<NameValuePair> qparams, CallingContext cc)
      throws IOException {

    HttpParams httpParams = new BasicHttpParams();
    HttpConnectionParams.setConnectionTimeout(
        httpParams, SOCKET_ESTABLISHMENT_TIMEOUT_MILLISECONDS);
    HttpConnectionParams.setSoTimeout(httpParams, SERVICE_TIMEOUT_MILLISECONDS);

    // setup client
    HttpClientFactory factory = (HttpClientFactory) cc.getBean(BeanDefs.HTTP_CLIENT_FACTORY);
    HttpClient client = factory.createHttpClient(httpParams);

    // support redirecting to handle http: => https: transition
    HttpClientParams.setRedirecting(httpParams, true);
    // support authenticating
    HttpClientParams.setAuthenticating(httpParams, true);

    // redirect limit is set to some unreasonably high number
    // resets of the socket cause a retry up to MAX_REDIRECTS times,
    // so we should be careful not to set this too high...
    httpParams.setParameter(ClientPNames.MAX_REDIRECTS, 32);
    httpParams.setParameter(ClientPNames.ALLOW_CIRCULAR_REDIRECTS, true);

    // context holds authentication state machine, so it cannot be
    // shared across independent activities.
    HttpContext localContext = new BasicHttpContext();

    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
    localContext.setAttribute(ClientContext.CREDS_PROVIDER, credsProvider);

    HttpUriRequest request = null;
    if (entity == null && (POST.equals(method) || PATCH.equals(method) || PUT.equals(method))) {
      throw new IllegalStateException("No body supplied for POST, PATCH or PUT request");
    } else if (entity != null
        && !(POST.equals(method) || PATCH.equals(method) || PUT.equals(method))) {
      throw new IllegalStateException("Body was supplied for GET or DELETE request");
    }

    URI nakedUri;
    try {
      nakedUri = new URI(url);
    } catch (Exception e) {
      e.printStackTrace();
      throw new IllegalStateException(e);
    }

    if (qparams == null) {
      qparams = new ArrayList<NameValuePair>();
    }
    URI uri;
    try {
      uri =
          new URI(
              nakedUri.getScheme(),
              nakedUri.getUserInfo(),
              nakedUri.getHost(),
              nakedUri.getPort(),
              nakedUri.getPath(),
              URLEncodedUtils.format(qparams, HtmlConsts.UTF8_ENCODE),
              null);
    } catch (URISyntaxException e1) {
      e1.printStackTrace();
      throw new IllegalStateException(e1);
    }
    System.out.println(uri.toString());

    if (GET.equals(method)) {
      HttpGet get = new HttpGet(uri);
      request = get;
    } else if (DELETE.equals(method)) {
      HttpDelete delete = new HttpDelete(uri);
      request = delete;
    } else if (PATCH.equals(method)) {
      HttpPatch patch = new HttpPatch(uri);
      patch.setEntity(entity);
      request = patch;
    } else if (POST.equals(method)) {
      HttpPost post = new HttpPost(uri);
      post.setEntity(entity);
      request = post;
    } else if (PUT.equals(method)) {
      HttpPut put = new HttpPut(uri);
      put.setEntity(entity);
      request = put;
    } else {
      throw new IllegalStateException("Unexpected request method");
    }

    HttpResponse resp = client.execute(request);
    return resp;
  }
  protected void postUploadTask(CallingContext cc) throws ODKExternalServiceException {
    // upload data to external service
    if (!fsc.getExternalServicePublicationOption()
        .equals(ExternalServicePublicationOption.STREAM_ONLY)) {

      UploadSubmissions uploadTask = (UploadSubmissions) cc.getBean(BeanDefs.UPLOAD_TASK_BEAN);
      CallingContext ccDaemon = ContextFactory.duplicateContext(cc);
      ccDaemon.setAsDaemon(true);
      uploadTask.createFormUploadTask(fsc, true, ccDaemon);
    }
  }