@Override
  public B2Object apply(HttpResponse from) {
    Payload payload = from.getPayload();
    MutableContentMetadata contentMeta = payload.getContentMetadata();

    String fileId = from.getFirstHeaderOrNull(B2Headers.FILE_ID);
    String fileName;
    try {
      fileName = URLDecoder.decode(from.getFirstHeaderOrNull(B2Headers.FILE_NAME), "UTF-8");
    } catch (UnsupportedEncodingException uee) {
      throw Throwables.propagate(uee);
    }
    String contentSha1 = from.getFirstHeaderOrNull(B2Headers.CONTENT_SHA1);
    ImmutableMap.Builder<String, String> fileInfo = ImmutableMap.builder();
    for (Map.Entry<String, String> entry : from.getHeaders().entries()) {
      if (entry
          .getKey()
          .regionMatches(
              true, 0, B2Headers.FILE_INFO_PREFIX, 0, B2Headers.FILE_INFO_PREFIX.length())) {
        String value;
        try {
          value = URLDecoder.decode(entry.getValue(), "UTF-8");
        } catch (UnsupportedEncodingException uee) {
          throw Throwables.propagate(uee);
        }
        fileInfo.put(entry.getKey().substring(B2Headers.FILE_INFO_PREFIX.length()), value);
      }
    }
    Date uploadTimestamp =
        new Date(Long.parseLong(from.getFirstHeaderOrNull(B2Headers.UPLOAD_TIMESTAMP)));
    String contentRange = from.getFirstHeaderOrNull(HttpHeaders.CONTENT_RANGE);

    return B2Object.create(
        fileId,
        fileName,
        null,
        null,
        contentMeta.getContentLength(),
        contentSha1,
        contentMeta.getContentType(),
        fileInfo.build(),
        null,
        uploadTimestamp.getTime(),
        contentRange,
        payload);
  }
  @Override
  protected HttpURLConnection convert(HttpRequest request)
      throws IOException, InterruptedException {
    boolean chunked = "chunked".equals(request.getFirstHeaderOrNull("Transfer-Encoding"));
    URL url = request.getEndpoint().toURL();

    HttpURLConnection connection =
        (HttpURLConnection) url.openConnection(proxyForURI.apply(request.getEndpoint()));
    if (connection instanceof HttpsURLConnection) {
      HttpsURLConnection sslCon = (HttpsURLConnection) connection;
      if (utils.relaxHostname()) sslCon.setHostnameVerifier(verifier);
      if (sslContextSupplier != null) {
        // used for providers which e.g. use certs for authentication (like FGCP)
        // Provider provides SSLContext impl (which inits context with key manager)
        sslCon.setSSLSocketFactory(sslContextSupplier.get().getSocketFactory());
      } else if (utils.trustAllCerts()) {
        sslCon.setSSLSocketFactory(untrustedSSLContextProvider.get().getSocketFactory());
      }
    }
    connection.setConnectTimeout(utils.getConnectionTimeout());
    connection.setReadTimeout(utils.getSocketOpenTimeout());
    connection.setAllowUserInteraction(false);
    // do not follow redirects since https redirects don't work properly
    // ex. Caused by: java.io.IOException: HTTPS hostname wrong: should be
    // <adriancole.s3int0.s3-external-3.amazonaws.com>
    connection.setInstanceFollowRedirects(false);
    try {
      connection.setRequestMethod(request.getMethod());
    } catch (ProtocolException e) {
      try {
        methodField.set(connection, request.getMethod());
      } catch (IllegalAccessException e1) {
        logger.error(e, "could not set request method: ", request.getMethod());
        propagate(e1);
      }
    }

    for (Map.Entry<String, String> entry : request.getHeaders().entries()) {
      connection.setRequestProperty(entry.getKey(), entry.getValue());
    }

    String host = request.getEndpoint().getHost();
    if (request.getEndpoint().getPort() != -1) {
      host += ":" + request.getEndpoint().getPort();
    }
    connection.setRequestProperty(HOST, host);
    if (connection.getRequestProperty(USER_AGENT) == null) {
      connection.setRequestProperty(USER_AGENT, DEFAULT_USER_AGENT);
    }
    Payload payload = request.getPayload();
    if (payload != null) {
      MutableContentMetadata md = payload.getContentMetadata();
      for (Map.Entry<String, String> entry : contentMetadataCodec.toHeaders(md).entries()) {
        connection.setRequestProperty(entry.getKey(), entry.getValue());
      }
      if (chunked) {
        connection.setChunkedStreamingMode(8196);
        writePayloadToConnection(payload, "streaming", connection);
      } else {
        Long length = checkNotNull(md.getContentLength(), "payload.getContentLength");
        // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6755625
        checkArgument(
            length < Integer.MAX_VALUE,
            "JDK 1.6 does not support >2GB chunks. Use chunked encoding, if possible.");
        if (length > 0) {
          connection.setRequestProperty(CONTENT_LENGTH, length.toString());
          connection.setFixedLengthStreamingMode(length.intValue());
          writePayloadToConnection(payload, length, connection);
        } else {
          writeNothing(connection);
        }
      }
    } else {
      writeNothing(connection);
    }
    return connection;
  }